洛谷 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;
}

猜你喜欢

转载自www.cnblogs.com/zzhzzh123/p/12228292.html