题解 区间加区间查询线段树裸题 用树状数组实现 常数小
/************************************************************** Problem: 3155 User: c20161007 Language: C++ Result: Accepted Time:464 ms Memory:4416 kb ****************************************************************/ #include <bits/stdc++.h> const int MAXN=1e5+10; #define ll long long using namespace std; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } ll a[MAXN],b[MAXN];int n,q; int get_id(int x){return x&(-x);} void add1(int x,ll vul){ if(x<=0)return ; for(int i=x;i<=n;i+=get_id(i))a[i]+=vul; return ; } void add2(int x,ll vul){ if(x<=0)return ; for(int i=x;i>0;i-=get_id(i))b[i]+=vul; } ll Sum1(int x){ if(x<=0)return 0; ll ans=0; for(int i=x;i>0;i-=get_id(i))ans+=a[i]; return ans; } ll Sum2(int x){ if(x<=0)return 0; ll ans=0; for(int i=x;i<=n;i+=get_id(i))ans+=b[i]; return ans; } ll A[MAXN],sum[MAXN]; int main(){ n=read();q=read(); for(int i=1;i<=n;i++)A[i]=read(); for(int i=1;i<=n;i++)sum[i]=A[i]+sum[i-1]; int p=n;n++; for(int i=1;i<=p;i++)add1(i,1ll*sum[i]*i),add2(i,sum[i]),add1(i-1,-1*sum[i]*(i-1)),add2(i-1,-1*sum[i]); char str[11];int pos;ll vul,key; for(int i=1;i<=q;i++){ scanf(" %s",str); if(str[0]=='Q')pos=read(),printf("%lld ",Sum1(pos)+1ll*pos*Sum2(pos+1)); else{ pos=read();vul=read();key=vul;vul-=A[pos];A[pos]=key; add1(p,1ll*vul*p),add2(p,vul); add1(pos-1,-1*vul*(pos-1)),add2(pos-1,-1*vul); } } return 0; }
3155: Preprefix sum
Time Limit: 1 Sec Memory Limit: 512 MB
Submit: 2060 Solved: 892
[Submit][Status][Discuss]
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
Sample Output
35
32
HINT
1<=N,M<=100000,且在任意时刻0<=Ai<=100000
Source
Katharon+#1