普通线段树,同时实现加,减,最大值操作
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define ll long long using namespace std; const int maxn=2e5+5; int A[maxn]; int tree[maxn<<2]; int n,m; int L,R,C; void pushup(int rt){ tree[rt]=tree[rt<<1]+tree[rt<<1|1];//因为不是求和,所以直接获取左右结点中大的数 } void build(int l,int r,int rt){ if(l==r){ tree[rt]=A[l]; return; } int m=(l+r)>>1;//线段树的平分方式 build(l,m,rt<<1);//左边,左子结点 build(m+1,r,rt<<1|1);//右边,右子结点 pushup(rt); } void update(int l,int r,int rt){ if(l==r){ tree[rt]+=C; return; } int m=(l+r)>>1; if(L<=m)update(l,m,rt<<1);//更新在左子树 else update(m+1,r,rt<<1|1);//更新在右子树 pushup(rt);//子结点已经更新,该结点也需要更新 } int query(int l,int r,int rt){ if(l>=L&&r<=R){ return tree[rt]; } int m=(l+r)>>1; int ans=0;//根据题意更新ans最小值 if(L<=m)ans=ans+query(l,m,rt<<1); if(m<R)ans=ans+query(m+1,r,rt<<1|1); return ans; } int main(){ int t; cin>>t; for(int j=1;j<=t;j++){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&A[i]); } build(1,n,1); //for(int i=1;i<=3*n;i++)printf("%d ",tree[i]); printf("Case %d:\n",j); while(1){ char str[15]; scanf("%s",str); if(str[0]=='E')break; else if(str[0]=='Q'){ scanf("%d%d",&L,&R); cout<<query(1,n,1)<<endl; }else if(str[0]=='A'){ scanf("%d%d",&L,&C); update(1,n,1); }else if(str[0]=='S'){ scanf("%d%d",&L,&C); C=-C; update(1,n,1); } } } return 0; }