POJ 3468 A Simple Problem with Integers(树状数组区间更新) 续

这个题刚开始的时候是套模板的,并没有真的理解什么树状数组的区间更新,这几天想了一下,下面是总结:

区间更新这里引进了一个数组delta数组,delta[i]表示区间 [i, n] 的共同增量,每次你需要更新的时候只需要更新delta数组就行了,因为每段区间更新的数都记录在这个数组中,那怎么查询前缀和呐?

sum[i]=a[1]+a[2]+a[3]+......+a[i]+delta[1]*(i-0)+delta[2]*(i-1)+delta[3]*(i-2)+......+delta[i]*(i-i+1);    

 

          = sigma( a[x] ) + sigma( delta[x]  *  (i + 1 - x) )  

          = sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )  

 

红字不难理解就是从当前位置到i区间共同的增量乘上当前位置到i有多少个数就是增加的总量;具体写到代码中怎么体现?还是以这个题为例:

 

#include<iostream>
#include<stdio.h>
#include<string.h>
#define N 100010
#define ll long long
using namespace std;
ll c1[N];//delta的前缀和   
ll c2[N];//delta * i的前缀和   
ll ans[N];//存放的前缀和
ll n,m;
string op;
ll lowbit(ll x)
{
    return x&(-x);
}
void update(ll x,ll val,ll *c)
{
    while(x<=n)
    {
        c[x]+=val;
        x+=lowbit(x);
    }
}
ll getsum(ll x,ll *c)
{
    ll s=0;
    while(x>0)
    {
        s+=c[x];
        x-=lowbit(x);
    }
    return s;
}
int main()
{
    freopen("C:\\Users\\acer\\Desktop\\in.txt","r",stdin);
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        memset(c1,0,sizeof c1);
        memset(c2,0,sizeof c2);
        memset(ans,0,sizeof ans);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&ans[i]);
            ans[i]+=ans[i-1];
        }
        getchar();
        for(int i=1;i<=m;i++)
        {
            cin>>op;
            if(op=="C")
            {
                ll s1,s2,s3;
                scanf("%lld%lld%lld",&s1,&s2,&s3);
                update(s1,s3,c1);//delta的前缀和  更新
                update(s2+1,-s3,c1);
                update(s1,s1*s3,c2);//delta * i的前缀和  更新
                update(s2+1,-(s2+1)*s3,c2);
            }
            else if(op=="Q")
            {
                /*
                sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )  
                */
                
                ll s1,s2;
                scanf("%lld%lld",&s1,&s2);
                /*sigma( a[x] )*/
                ll cur=ans[s2]-ans[s1-1];//首先等于s1~s2这个区间的基础值
                /*(i + 1) * sigma( delta[x] )*/
                cur+=getsum(s2,c1)*(s2+1)-getsum(s2,c2);//0~s2对前缀和的影响
                /*sigma( delta[x] * x )*/  
                cur-=getsum(s1-1,c1)*(s1)-getsum(s1-1,c2);//0~s1对前缀和的影响
                printf("%lld\n",cur);
            }
        }
    }
}

 

posted @ 2016-09-19 22:26  勿忘初心0924  阅读(141)  评论(0编辑  收藏  举报