首页 > 代码库 > POJ 3468 A Simple Problem with Integers 【树状数组】

POJ 3468 A Simple Problem with Integers 【树状数组】

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

题目大意:给出一组数组v[i],有两种操作,一种给出两个数a,b,要求输出v[a]到v[b]之间的和,另一种给出三个数a,b,c,让v[a]到v[b]之间的数全都加上c。

完全是树状数组能够实现的功能,但是如果就这样单纯的套用模板,做第二种操作是更新每个值,这样的操作就有可能超时。

换一种思路,既然第二种操作是给某区间上的所有数加上相同的值,那么应该是能够简化的才对。

假设数组sum[i]为原数组从v[1]到v[i]的和,数组c1[i]为更新之后,v[i]到v[n]的增加量,分析一下结果ans:

a,b之间的和ans=sum[b]-sum[a-1]+c1[1]*x + c1[2]*(x-1) + c1[3]*(x-2)+...+c1[x]*1

ans=sum[b]-sum[a-1]+segema(c1[i]*(x-i+1))

ans=sum[b]-sum[a-1] + (x+1)*segma(c1[i]) - segma(c1[i]*i)

令c2[i]=c1[i]*i;

如此便能利用树状数组解出此题

代码:

#include <stdio.h>
#define N 100001
#define lowbit(i) ( i & (-i) )
int n;
__int64 v[N];
__int64 c1[N];// 每个C数组代表v[i-lowbit(i)+1]到v[i]之间的和
__int64 c2[N];
__int64 sum[N];

void Updata(__int64 *array,__int64 i,__int64 a)
{
    for(;i<=n;i+=lowbit(i))
        array[i]+=a;
}
__int64 Sumv(__int64 *array,__int64 i)   //求出数组v[1]到v[i]的和
{
    __int64 result=0;
    while (i>=1)
    {
        result+=array[i];
        i-=lowbit(i);
    }
    return result;
}
int main()
{
    __int64 q,i=0;
    __int64 ans=0;
    scanf("%I64d%I64d",&n,&q);
    for(i=1;i<=n;i++)
        scanf("%I64d",&v[i]);
    for(__int64 i=1;i<=n;i++)
        sum[i]=sum[i-1]+v[i];
    while(q--)
    {
        char ch[2];
        scanf("%s",ch);
        if(ch[0]=='Q')
        {
            __int64 s,t;
            scanf("%I64d%I64d",&s,&t);
            ans=sum[t]-sum[s-1];
            ans+=((t+1)*Sumv(c1,t)-Sumv(c2,t));
            ans-=(s*Sumv(c1,s-1)-Sumv(c2,s-1));
            printf("%I64d\n",ans);
        }
        else
        {
            __int64 a,b,c;
            scanf("%I64d%I64d%I64d",&a,&b,&c);
            Updata(c1,a,c);
            Updata(c1,b+1,-c);
            Updata(c2,a,c*a);
            Updata(c2,b+1,-c*(b+1));
        }
    }
    return 0;
}