Description
有一个长度为n的整数数列a。
现在有m个操作,操作的格式有两种:
1 x y,表示修改,将数列第x个数a[x]改为a[x]+y;
2 x y, 表示询问,询问第x个数到第y个数间,最大的一个数是多少。
Input
第一行,两个整肃n和m
第二行,n个空格间隔的整数,表示数列a
接下来m行,每行三个整数k,x和y,表示一个操作,k=1表示修改,k=2表示询问
Output
若干行,每行对应一个询问的结果
Sample Input
7 5
-1 6 5 3 4 9 7
1 4 5
2 2 6
2 1 3
1 6 -8
2 2 6
Sample Output
9
6
8
裸的线段树,主要是细节,直接放代码了:
注意,位运算的优先级较低,例如(x>>1)+1不能写成 x>>1+1;
代码如下:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=100000+5,inf=2e9; int n,m,maxv[maxn*20]; //大小为maxn*log2(maxn); void _read(int &x){ char ch;bool mark=false; for(ch=getchar();!isdigit(ch);ch=getchar()) if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } struct segment_tree{ int s[maxn]; int ql,qr,n,p,v; //ql,qr为当前query询问的区间左右端点; //p,v表示更新数据 s[p]=v; void init(int n){ for(int i=1;i<=maxn;i++)maxv[i]=inf; memset(s,0,sizeof(s)); this->n=n; } int _query(int o,int L,int R){ //当前端点o,左端点为L ,右端点为R; int ans=-inf; int mid=(L+R)>>1; if(ql<=L&&qr>=R) return maxv[o]; //当前节点被完全包含在ql,qr中; if(mid>=ql) ans=max(ans,_query(o<<1,L,mid)); // 往左走 if(mid<qr) ans=max(ans,_query((o<<1)+1,mid+1,R)); // 往右走 return ans; } int query(int l,int r){ ql=l;qr=r; return _query(1,1,n); } void _update(int o,int L,int R){ int mid=(L+R)>>1; if(L==R)maxv[o]=v; else { if(p<=mid)_update((o<<1),L,mid); else _update((o<<1)+1,mid+1,R); maxv[o]=max(maxv[o<<1],maxv[(o<<1)+1]); //不能写在else外面 } } int update(int x,int y){ s[x]=y; //不要忘了修改S数组的值,否则多次修改会出错 p=x;v=y; _update(1,1,n); } void build(int o,int L,int R){ //建树 int mid=(L+R)>>1; if(L==R) maxv[o]=s[L]; else { build((o<<1),L,mid); build((o<<1)+1,mid+1,R); //建左右子树 maxv[o]=max(maxv[o<<1],maxv[(o<<1)+1]); //建当前节点o } } }; segment_tree tree; int main(){ _read(n);_read(m); tree.init(n); for(int i=1;i<=n;i++)_read(tree.s[i]); tree.build(1,1,n); while(m--){ int k,x,y; _read(k);_read(x);_read(y); if(k==1)tree.update(x,tree.s[x]+y); else printf("%d\n",tree.query(x,y)); } }