【传送门:BZOJ3155】
简要题意:
给出一个序列a[i],s[i]表示a[1]到a[i]的和,ss[i]表示s[1]到s[i]的和,对于这个序列有两种操作:
1.Query x,输出ss[x]
2.Modify x d,将a[x]改为d
题解:
本来想用树状数组,结果写炸了
还是老老实实写线段树
将s数组作为叶子节点的值存进线段树,对于第一种操作只需要输出1到x的和就可以了,而第二种操作因为是区间修改,所以用lazy标记来进行继承,对于每次修改,将tr[x].c+=(tr[x].r-tr[x].l+1)*c,这样就能维护值了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; struct node { int l,r,lc,rc;LL c; LL lazy; }tr[210000];int trlen; LL a[110000],s[110000]; void bt(int l,int r) { trlen++;int now=trlen; tr[now].l=l;tr[now].r=r; tr[now].lc=tr[now].rc=-1; tr[now].lazy=0; if(l==r) tr[now].c=s[l]; else { int mid=(l+r)/2; tr[now].lc=trlen+1;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); tr[now].c=tr[tr[now].lc].c+tr[tr[now].rc].c; } } void update(int x) { int lc=tr[x].lc,rc=tr[x].rc; if(lc!=-1) { tr[lc].c+=LL(tr[lc].r-tr[lc].l+1)*tr[x].lazy; tr[lc].lazy+=tr[x].lazy; } if(rc!=-1) { tr[rc].c+=LL(tr[rc].r-tr[rc].l+1)*tr[x].lazy; tr[rc].lazy+=tr[x].lazy; } tr[x].lazy=0; } LL getsum(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) return tr[now].c; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=0) update(now); if(r<=mid) return getsum(lc,l,r); else if(l>mid) return getsum(rc,l,r); else return getsum(lc,l,mid)+getsum(rc,mid+1,r); tr[now].c=tr[lc].c+tr[rc].c; } void change(int now,int l,int r,LL c) { if(tr[now].l==l&&tr[now].r==r) { tr[now].lazy+=c; tr[now].c+=LL(r-l+1)*c; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=0) update(now); if(r<=mid) change(lc,l,r,c); else if(l>mid) change(rc,l,r,c); else { change(lc,l,mid,c); change(rc,mid+1,r,c); } tr[now].c=tr[lc].c+tr[rc].c; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); s[0]=0; for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i]; trlen=0;bt(1,n); char st[11]; for(int i=1;i<=m;i++) { int x; scanf("%s%d",st+1,&x); if(st[1]==‘Q‘) printf("%lld\n",getsum(1,1,x)); else { LL d; scanf("%lld",&d); change(1,x,n,d-a[x]); a[x]=d; } } return 0; }