BZOJ3155: Preprefix sum
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
题解Here!
树状数组神题。。。
开两个树状数组,第一个维护$val[i]$前缀和。
第二个维护$val[i]*(n-i+1)$的前缀和。
修改就是加上$x-val[i]$。
查询的话就是$query2(x)-query1(x)*(n-x)$。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 100010 using namespace std; int n,m; long long val[MAXN],bit_one[MAXN],bit_two[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline int lowbit(int x){return x&(-x);} inline void update_one(int x,long long v){for(;x<=n;x+=lowbit(x))bit_one[x]+=v;} inline long long query_one(int x){long long s=0;for(;x;x-=lowbit(x))s+=bit_one[x];return s;} inline void update_two(int x,long long v){for(;x<=n;x+=lowbit(x))bit_two[x]+=v;} inline long long query_two(int x){long long s=0;for(;x;x-=lowbit(x))s+=bit_two[x];return s;} void work(){ char ch[10]; int x; while(m--){ scanf("%s",ch);x=read(); if(ch[0]=='M'){ long long k=read(); update_one(x,k-val[x]); update_two(x,(k-val[x])*(n-x+1)); val[x]=k; } else printf("%lld\n",query_two(x)-query_one(x)*(n-x)); } } void init(){ n=read();m=read(); for(int i=1;i<=n;i++){ val[i]=read(); update_one(i,val[i]); update_two(i,val[i]*(n-i+1)); } } int main(){ init(); work(); return 0; }