[bzoj-3155]Preprefix sum 题解

题目传送门
题意解析:题目给了一个a序列,并且定义s为a序列的前缀和,ss为s序列的前缀和,然后有两种操作,一种是查询ss[i]的值,还有一种是修改a[i]。


My opinion:明显的数据结构题,但是怎么维护是一个问题,我们列出a,s,ss就会发现一些现象。
a a1 a2 a3 a4 a5 a6 …… an
s a1 a1+a2 a1+a2+a3 …… a1+a2+……+an
ss a1 2a1+a2 3a1+2a2+a3 …… na1+(n-1)a2+……+an
从上我们可以看出,每一个ai在一个ssj中(i<=j),ai有(j-i+1)个
所以这题我们只需要维护ai的前缀和和(n-i+1)*ai的前缀和就可以了。
最后答案的计算就是(n-i+1)*ai的前缀和减去ai的前缀和乘上(n-i)。
所以我们可以用各种数据结构维护,不过因为维护的区间是1-i(有可能没啥用),所以我用了树状数组。
总结:
1、输入,并加入树状数组。
2、对于每个操作做出相应的反应。


结构体大法好:

#include
#include
#include
#include
#include
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define ll long long
#define INF 2000000000
#define eps 1e-8
using namespace std;
int read(){
    int x=0,f=1; 
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=100005;
int a[maxn];
int lowbit(int x){
    return x&(-x);
}
int n,m;
struct tree{
    ll tr[maxn];
    inline void add(int x,ll d){
        for (int i=x;i<=n;i+=lowbit(i))
            tr[i]+=d;
    }
    inline ll sum(int x){
        ll ans=0;
        for (int i=x;i;i-=lowbit(i))
            ans+=tr[i];
        return ans;
    }
}tr1,tr2;
int main(){
    n=read(),m=read();
    rep(i,1,n){
        a[i]=read();
        tr1.add(i,a[i]);
        tr2.add(i,(ll)(n-i+1)*a[i]);    
    }
    rep(i,1,m){
        char op[10];
        scanf("%s",op);
        if (op[0]=='Q'){
            int x=read();
            printf("%lld\n",tr2.sum(x)-tr1.sum(x)*(n-x));
        }else{
            int x=read(),y=read();
            tr1.add(x,y-a[x]);
            tr2.add(x,(ll)(n-x+1)*(y-a[x]));
            a[x]=y;
        }
    }
    return 0;
}

你可能感兴趣的:(bzoj,树状数组)