洛谷 P4868 Preprefix sum

题目链接

本题与我的树状数组进阶有类似之处,基本上思路完全一样

我们对\(SS[i]\)进行分析

\[S[i]=\sum_{k=1}^{i} A[k] \]

\[SS[i]=\sum_{k=1}^{i} S[k] \]

\[SS[i]=\sum_{k=1}^{i} \sum_{j=1}^{k} A[j] \]

\[SS[i]=(i+1) * \sum_{k=1}^{i} A[k] - \sum_{k=1}^{i} A[k] * k \]

显然我们只需要维护两个树状数组,分别是\(A[i]\),\(A[i]*i\)的前缀和

[Code]


#include <bits/stdc++.h>
using namespace std;

int read(){
	int x=0,flag=1; char c;
	for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
	for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
	return x*flag;
}

const int N=1e5+50;

int n,m;
int a[N]; 
long long c1[N],c2[N];//c1:a[i]前缀和,c2:a[i]*i前缀和

int lowbit(int x) { return x&(-x); }
void update(int x,int y){
    for(int i=x;i<=n;i+=lowbit(i)) c1[i]+=y,c2[i]+=1ll*y*x; //分别维护c1,c2
}
long long query(int x){
    long long ret=0;
	for(int i=x;i>0;i-=lowbit(i)) ret+=1ll*(x+1)*c1[i]-c2[i];//直接套公式计算
	return ret; 
}

int main() {
    n=read(),m=read();
    for(int i=1;i<=n;i++){
	    a[i]=read(); update(i,a[i]);
	}
	
	while(m--){
	    char s[105];
	    int x,y;
	    scanf(" %s %d",s,&x);
	    if(s[0]=='Q'){
		    printf("%lld\n",query(x));
		}
		if(s[0]=='M'){
		    y=read();
		    update(x,y-a[x]);//差值更新
		    a[x]=y;
		}
	}
	return 0;
}

posted @ 2020-01-22 11:46  zhuzihan  阅读(87)  评论(0编辑  收藏  举报