Description
Input
第一行给出两个整数N,M。分别表示序列长度和操作个数
接下来一行有N个数,即给定的序列a1,a2,....an
接下来M行,每行对应一个操作,格式见题目描述
Output
对于每个询问操作,输出一行,表示所询问的SSi的值。
Sample Input
5 3
1 2 3 4 5
Query 5
Modify 3 2
Query 5
1 2 3 4 5
Query 5
Modify 3 2
Query 5
Sample Output
35
32
32
HINT
1<=N,M<=100000,且在任意时刻0<=Ai<=100000
Solution
直接用线段树维护一次前缀和的数组$S$,然后修改后缀,查询前缀。注意常数。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (100009) 5 #define LL long long 6 using namespace std; 7 8 struct Sgt{LL val,add;}Segt[N<<2]; 9 int n,m,x,y; 10 LL a[N],S[N]; 11 char opt[10]; 12 13 inline int read() 14 { 15 int x=0; char c=getchar(); 16 while (c<'0' || c>'9') c=getchar(); 17 while (c>='0' && c<='9') x=x*10+c-'0', c=getchar(); 18 return x; 19 } 20 21 void Pushdown(int now,int l,int r) 22 { 23 if (Segt[now].add) 24 { 25 int mid=(l+r)>>1; 26 Segt[now<<1].add+=Segt[now].add; 27 Segt[now<<1|1].add+=Segt[now].add; 28 Segt[now<<1].val+=Segt[now].add*(mid-l+1); 29 Segt[now<<1|1].val+=Segt[now].add*(r-mid); 30 Segt[now].add=0; 31 } 32 } 33 34 void Update(int now,int l,int r,int l1,int r1,LL k) 35 { 36 if (l>r1|| r<l1) return; 37 if (l1<=l && r<=r1) 38 { 39 Segt[now].add+=k; 40 Segt[now].val+=(r-l+1)*k; 41 return; 42 } 43 int mid=(l+r)>>1; Pushdown(now,l,r); 44 Update(now<<1,l,mid,l1,r1,k); 45 Update(now<<1|1,mid+1,r,l1,r1,k); 46 Segt[now].val=Segt[now<<1].val+Segt[now<<1|1].val; 47 } 48 49 LL Query(int now,int l,int r,int l1,int r1) 50 { 51 if (l>r1|| r<l1) return 0; 52 if (l1<=l && r<=r1) return Segt[now].val; 53 int mid=(l+r)>>1; Pushdown(now,l,r); 54 return Query(now<<1,l,mid,l1,r1)+Query(now<<1|1,mid+1,r,l1,r1); 55 } 56 57 int main() 58 { 59 n=read(); m=read(); 60 for (int i=1; i<=n; ++i) 61 a[i]=read(), S[i]=S[i-1]+a[i], Update(1,1,n,i,i,S[i]); 62 while (m--) 63 { 64 scanf("%s",&opt); x=read(); 65 if (opt[0]=='Q') printf("%lld ",Query(1,1,n,1,x)); 66 else y=read(), Update(1,1,n,x,n,y-a[x]), a[x]=y; 67 } 68 }