问题描述
有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;
}
}