問題描述
有n個格子,從左到右放成一排,編號爲1-n。
共有m次操作,有3種操作類型:
1.修改一個格子的權值,
2.求連續一段格子權值和,
3.求連續一段格子的最大值。
對於每個2、3操作輸出你所求出的結果。
輸入格式
第一行2個整數n,m。
接下來一行n個整數表示n個格子的初始權值。
接下來m行,每行3個整數p,x,y,p表示操作類型,p=1時表示修改格子x的權值爲y,p=2時表示求區間[x,y]內格子權值和,p=3時表示求區間[x,y]內格子最大的權值。
輸出格式
有若干行,行數等於p=2或3的操作總數。
每行1個整數,對應了每個p=2或3操作的結果。
樣例輸入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
樣例輸出
6
3
數據規模與約定
對於20%的數據n <= 100,m <= 200。
對於50%的數據n <= 5000,m <= 5000。
對於100%的數據1 <= n <= 100000,m <= 100000,0 <= 格子權值 <= 10000。
方法一(不適用數據太大的情況,容易超時)
import java.util.Scanner;
public class Main3
{
final static int MAX_N = 400010; //定義一個靜態的最大值
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
Main3 a=new Main3();//調用非靜態方法需要先創建一個對象
a.Build(1,1,n); //構建一個從1到n的線段樹
int value;//每個格子的權值
for(int i=1;i<=n;i++)
{
value=sc.nextInt();
a.Insert(1,i,value); //向已有線段數中插入權值
}
while(m!=0)
{
int p=sc.nextInt();
int x=sc.nextInt();
int y=sc.nextInt();
switch(p)
{
case 1:a.Update(1,x,y);break; //修改格子x的權值爲y;
case 2:System.out.println(a.Qsum(1,x,y));break; //求區間[x,y]內的權值和
case 3:System.out.println(a.Qmax(1,x,y));break; //求區間[x,y]內格子的最大權值
}
m--;
}
}
class Node //構建一個線段樹的結點的類
{
int left,right; //區間[left,right]
int sum, max; //sum爲區間[left,right]權值和,max爲區間的最大值
Node () {}
Node (int _l, int _r, int _s, int _m) {
left = _l;
right = _r;
sum = _s;
max = _m;
}
}
Node tree[] = new Node[MAX_N];//定義線段樹結點的空間
void Build(int i,int left,int right)//i爲數組下標,稱作結點序號,爲區間[left,right]建立一個以i爲祖先的線段樹
{
tree[i] = new Node(left, right, 0, 0);
if(left==right)
return ;
Build(i*2,left,(left+right)/2); //構建left至(left+right)/2的左孩子;
Build(i*2+1,(left+right)/2+1,right);//構建右孩子;
}
void Insert(int i,int n,int value) //爲線段樹插入一個值
{
tree[i].sum+=value; //區間的權值和
if(tree[i].max<value)
tree[i].max=value; //最大值
if(tree[i].left==tree[i].right) //左右邊距相等不再插入新值
return ;
if(n<=(tree[i].left+tree[i].right)/2)
Insert(i*2,n,value); //更新左孩子
else
Insert(i*2+1,n,value); //更新右孩子
}
void Update(int i,int n,int value)
{
if(n==tree[i].left && n==tree[i].right) //下標與左右範圍相等,存本數
{
tree[i].sum=value;
tree[i].max=value;
return;
}
int mid=(tree[i].left+tree[i].right)/2;
if(n<=mid)
Update(i*2,n,value);
else
Update(i*2+1,n,value);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; //更新總和
tree[i].max=Math.max(tree[i*2].max,tree[i*2+1].max); //更新最大值
}
int Qsum(int i,int left,int right) //求權值和
{
if(left==tree[i].left && right==tree[i].right)
return tree[i].sum;
int mid=(tree[i].left+tree[i].right)/2;
if(right<=mid)
return Qsum(i*2,left,right);
else if(left>mid)
return Qsum(i*2+1,left,right);
else return Qsum(i*2,left,mid)+Qsum(i*2+1,mid+1,right);//若範圍在左右孩子之間,分別求總和
}
int Qmax(int i,int left,int right)
{
if(left==tree[i].left && right==tree[i].right)
return tree[i].max;
int mid=(tree[i].left+tree[i].right)/2;
if(right<=mid)
return Qmax(i*2,left,right);
else if(left>mid)
return Qmax(i*2+1,left,right);
else return Math.max(Qmax(i*2,left,mid), Qmax(i*2+1,mid+1,right));
}
}
方法二(適用於大數據)
import java.io.*;
import java.util.*;
public class Main2{
final static int MAX_N = 400010;
class Node
{
int left,right;
int sum, max;
Node () {}
Node (int _l, int _r, int _s, int _m) {
left = _l;
right = _r;
sum = _s;
max = _m;
}
}
int n, m;
Node tree[] = new Node[MAX_N];
int a[] = new int[MAX_N];
void up(int id) {
tree[id].sum = tree[id*2].sum + tree[id*2+1].sum;
tree[id].max = Math.max(tree[id*2].max, tree[id*2+1].max);
}
void Build(int i,int left,int right)
{
tree[i] = new Node(left, right, 0, 0);
if(left==right)
return ;
Build(i*2,left,(left+right)/2);
Build(i*2+1,(left+right)/2+1,right);
}
void Insert(int i,int n,int value)
{
tree[i].sum+=value;
if(tree[i].max<value)
tree[i].max=value;
if(tree[i].left==tree[i].right)
return ;
if(n<=(tree[i].left+tree[i].right)/2)
Insert(i*2,n,value);
else
Insert(i*2+1,n,value);
}
void Update(int i,int n,int value)
{
if(n==tree[i].left && n==tree[i].right)
{
tree[i].sum=value;
tree[i].max=value;
return;
}
int mid=(tree[i].left+tree[i].right)/2;
if(n<=mid)
Update(i*2,n,value);
else
Update(i*2+1,n,value);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
tree[i].max=Math.max(tree[i*2].max,tree[i*2+1].max);
}
int Qsum(int i,int left,int right)
{
if(left==tree[i].left && right==tree[i].right)
return tree[i].sum;
int mid=(tree[i].left+tree[i].right)/2;
if(right<=mid)
return Qsum(i*2,left,right);
else if(left>mid)
return Qsum(i*2+1,left,right);
else return Qsum(i*2,left,mid)+Qsum(i*2+1,mid+1,right);
}
int Qmax(int i,int left,int right)
{
if(left==tree[i].left && right==tree[i].right)
return tree[i].max;
int mid=(tree[i].left+tree[i].right)/2;
if(right<=mid)
return Qmax(i*2,left,right);
else if(left>mid)
return Qmax(i*2+1,left,right);
else return Math.max(Qmax(i*2,left,mid), Qmax(i*2+1,mid+1,right));
}
void run() throws IOException {
n = cin.nextInt();
m = cin.nextInt();
Build(1, 1, n);
int value;
for(int i=1;i<=n;i++)
{
value=cin.nextInt();
Insert(1,i,value);
}
for (int i = 0; i < m; ++i) {
int type = cin.nextInt();
int l = cin.nextInt();
int r = cin.nextInt();
if (type == 1) Update(1, l, r);
else if (type == 2) out.println(Qsum(1, l, r));
else out.println(Qmax(1, l, r));
}
out.close();
}
public static void main(String[] args) throws IOException {
new Main2().run();
}
Main2() {
cin = new InputReader(System.in);
out = new PrintWriter(System.out);
}
PrintWriter out;
InputReader cin;
class InputReader {
InputReader(InputStream in) {
reader = new BufferedReader(new InputStreamReader(in));
tokenizer = new StringTokenizer("");
}
private String next() throws IOException {
while (!tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
public Integer nextInt() throws IOException {
return Integer.parseInt(next());
}
private BufferedReader reader;
private StringTokenizer tokenizer;
}
}