一个点更新,区间查询的线段树,不过点可以当成一个长度为1的区间,所以我直接采用了区间更新的办法,用lazy数组存储更新状态,使用到才更新,更加省时间。代码如下
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>using namespace std;const int MAXN=50010;
int a[MAXN],ans[MAXN<<2],lazy[MAXN<<2];void PushUp(int rt)
{ans[rt]=ans[rt<<1]+ans[rt<<1|1];
}void Build(int l,int r,int rt)
{if (l==r){ans[rt]=a[l];return;}int mid=(l+r)>>1;Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);PushUp(rt);
}void PushDown(int rt,int ln,int rn)//ln表示左子树元素结点个数,rn表示右子树结点个数
{if (lazy[rt]){lazy[rt<<1]+=lazy[rt];lazy[rt<<1|1]+=lazy[rt];ans[rt<<1]+=lazy[rt]*ln;ans[rt<<1|1]+=lazy[rt]*rn;lazy[rt]=0;}
}void Add(int L,int C,int l,int r,int rt)
{if (l==r){ans[rt]+=C;return;}int mid=(l+r)>>1;//PushDown(rt,mid-l+1,r-mid); 若既有点更新又有区间更新,需要这句话if (L<=mid)Add(L,C,l,mid,rt<<1);elseAdd(L,C,mid+1,r,rt<<1|1);PushUp(rt);
}void Update(int L,int R,int C,int l,int r,int rt)
{if (L<=l&&r<=R){ans[rt]+=C*(r-l+1);lazy[rt]+=C;return;}int mid=(l+r)>>1;PushDown(rt,mid-l+1,r-mid);if (L<=mid) Update(L,R,C,l,mid,rt<<1);if (R>mid) Update(L,R,C,mid+1,r,rt<<1|1);PushUp(rt);
}int Query(int L,int R,int l,int r,int rt)
{if (L<=l&&r<=R)return ans[rt];int mid=(l+r)>>1;PushDown(rt,mid-l+1,r-mid);//若更新只有点更新,不需要这句int ANS=0;if (L<=mid) ANS+=Query(L,R,l,mid,rt<<1);if (R>mid) ANS+=Query(L,R,mid+1,r,rt<<1|1);return ANS;
}int main()
{int T, n, p, q, t = 1;string s;cin >> T;while(T--) {memset(lazy, 0, sizeof(lazy));memset(ans, 0, sizeof(ans));cin >> n;for(int i = 1; i <= n; i++) {cin >> a[i];}printf("Case %d:\n", t++);Build(1, n, 1);while(cin >> s && s[0] != 'E') {cin >> p >> q;if(s[0] == 'S') {q = -q;Update(p, p, q, 1, n, 1);}else if(s[0] == 'A') {Update(p, p, q, 1, n, 1);}else {printf("%d\n", Query(p, q, 1, n, 1));}}}return 0;
}