题目大意:多次求出定区间上的最大值和区间上元素之和。因为这里可能求解的次数达到100000次,而数组长度最大也为100000,我们知道求最大值和元素之和,若是用数组存储,最快也要O(n)的时间才能完成,这样的话,必然超时。
题目分析:根据提示,我们使用线段树来解决,使得在区间上求和、求最大值的时间复杂度在O(logn)
建立线段树、插值、查询最大值、查询和都需要递归操作,对一个树的操作,就是分别对于左子树和右子树递归操作。另外,注意这里所需要的存储空间大小,要开辟100010的3倍以上才行。
代码实现:
#include <iostream>
#include <algorithm>
using namespace std;
#define Large_data MAX_INT
int num[100010];
int sum[100010*4],maxx[100010*4];
int n,m;
void buildtree(int i,int l,int r){ //建立线段树
if(l==r){
sum[i] = maxx[i] = num[l];
return;
}
int mid = (l+r)/2;
buildtree(i*2,l,mid);
buildtree(i*2+1,mid+1,r);
maxx[i] = max(maxx[i*2],maxx[i*2+1]);
sum[i] = sum[i*2] + sum[i*2+1];
return;
}
void setValue(int i,int l,int r,int x,int y){
if(l==r){
maxx[i] = sum[i] = num[x] = y;
return;
}
int mid = (l+r)/2;
if(x<=mid)
setValue(i*2,l,mid,x,y);
else
setValue(i*2+1,mid+1,r,x,y);
maxx[i] = max(maxx[i*2],maxx[i*2+1]);
sum[i] = sum[i*2] + sum[i*2+1];
}
int querysum(int i,int l,int r,int x,int y){
if(x>r || y<l)
return 0;
else if(x<=l && r<=y)
return sum[i];
int mid = (l+r)/2;
int lsum = 0,rsum = 0;
if(mid>=x)
lsum = querysum(i*2,l,mid,x,y);
if(mid<y)
rsum = querysum(i*2+1,mid+1,r,x,y);
return lsum+rsum;
}
int querymax(int i,int l,int r,int x,int y){
if(x>r || y<l)
return 0;
else if(x<=l && r<=y)
return maxx[i];
int mid = (l+r)/2;
int lmax = 0,rmax = 0;
if(mid>=x)
lmax = querymax(i*2,l,mid,x,y);
if(mid<y)
rmax = querymax(i*2+1,mid+1,r,x,y);
return max(lmax,rmax);
}
int main(){
int p,x,y;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>num[i];
}
buildtree(1,1,n);
for(int i=1;i<=m;i++){
cin>>p>>x>>y;
if(p==1)
setValue(1,1,n,x,y);
else if(p==2)
cout<<querysum(1,1,n,x,y)<<endl;
else
cout<<querymax(1,1,n,x,y)<<endl;
}
return 0;
}