POJ 3468 A Simple Problem with Integers

Description
给出了一个序列,你需要处理如下两种询问。

"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。

"Q a b" 询问[a, b]区间中所有值的和。

Input
第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.

第二行包含n个整数,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。

接下来Q行询问,格式如题目描述。

Output
对于每一个Q开头的询问,你需要输出相应的答案,每个答案一行。

Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9

15

这道题是对一个区间中所有点进行更新,然后求区间和。

#include<stdio.h>
#include<iostream>
#include<string.h>
#define MAXN 100000+10
using namespace std;
long long initsum[MAXN];
long long c1[MAXN],c2[MAXN];
int n;

int lowbit(int x)///利用计算机补码计算2^k(其中k为x二进制末尾0的个数)
{
    return x&(-x);
}
void add(long long *c,int i,int val)///修改操作,更新C[i],如果A[i]发生改变,那么C[i]节点发生改变,C[i]的祖先也发生改变。
{
    while(i<=n)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
int sum(long long *c,int i)///计算前i项的和
{
    int s=0;
    while(i>0)
    {
        s+=c[i];
        i-=lowbit(i);
    }
    return s;
}
int main()
{
    int m,a,b,e,t;
    long long ans;
    char str[2];
    while(~scanf("%d%d",&n,&m))
    {
        memset(c1,0,sizeof(c1));
         memset(c2,0,sizeof(c2));
           memset(initsum, 0, sizeof (initsum)); 
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&t);
            initsum[i] = initsum[i-1] + t;
        }
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='Q')
            {
                scanf("%d%d",&a,&b);
                ans=initsum[b]-initsum[a-1];
                ans+=(b+1)*sum(c1,b)-sum(c2,b);
                ans-=(a*sum(c1,a-1)-sum(c2,a-1));
                printf("%lld\n",ans);
            }
            else
            {
                    scanf("%d%d%d",&a,&b,&e);
                    add(c1,a,e);
                    add(c2,a,a*e);///这两个add后,区间c[a...n]每个数都增加了c。
                    add(c1,b+1,-e);
                    add(c2,b+1,-(b+1)*e); ///这两个update后,区间c[b+1...n]每个数都减少了c 
            }
        }
    }
}


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