POJ3468——树状数组支持两个区间操作

题目:http://poj.org/problem?id=3468

推断过程可自己查,得式子:fixsum(x) = (x+1) * ∑(i=1,x)fi - ∑(i=1,x)i*fi;

其中 f 是真实值的修改量,故修改区间变为f的单点修改,求真实值时取f的前缀和加上自己的原值(真实值)。

故修改i*fi时也是普通的单点修改,再普通维护树状数组,每个影响的部分和都加上这个固定值。

最后求前缀和时用fixsum加上原前缀和得到修改后的。

#include<iostream>
#include<cstdio>
using namespace std;
int n,t,L,R,c;
long long a[100005],f[100005],fi[100005],s[100005];
char ch;
void add(int x,int c)
{
    int y=x;
    for(;x<=n;x+=x&-x)
    {
        f[x]+=c;
        fi[x]+=y*c;
    }
}
long long query(int x)
{
    long long fis=0,fs=0;
    int y=x;
    for(;x;x-=x&-x)
        fis+=fi[x],fs+=f[x];
    return (y+1)*fs-fis;
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        s[i]=s[i-1]+a[i];
    }
    while(t--)
    {
        scanf(" %c",&ch);
        if(ch=='C')
        {
            scanf("%d%d%d",&L,&R,&c);
            add(L,c);add(R+1,-c);
        }
        else
        {
            scanf("%d%d",&L,&R);
            printf("%lld\n",(query(R)+s[R])-(query(L-1)+s[L-1]));
        }
    }
    return 0;
}

 

posted on 2018-02-10 22:58  Narh  阅读(138)  评论(0编辑  收藏  举报

导航