POJ3468树状数组

题目:题目链接

 

题意:

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.The second line contains N numbers,

the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.Each of the next Q lines

represents an operation."C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.

"Q a b" means querying the sum of AaAa+1, ... , Ab.

就是区间更新,求区间总和sum,树状数组(或者线段树):

 

Sum[x] = SUM(A[i], i=1...x)+(x+1)*SUM(delta[i],i=1...x)-SUM(i*delta[i],i=1...x)在成段更新时,是对delta

数组进行更新,于是用两个树状数组t1,t2来维护两个前缀和SUM(delta[i],i=1...x),SUM(i*delta[i],i=1...x),而

SUM(A[i], i=1...x)在更新过程中是不变的,所以可以预处理在数组中将区间的成段更新转化成对t1,t2两个树状数

组的单点更新,使更新复杂度保持O(log(n))

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <functional>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <bitset>
#include <stack>
#include <ctime>
#include <list>
#define INF 0x7fffffff
#define max3(a,b,c) (max(a,b)>c?max(a,b):c)
#define min3(a,b,c) (min(a,b)<c?min(a,b):c)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
#define maxn 100005

__int64 sum[maxn];
__int64 t1[maxn];
__int64 t2[maxn];

inline __int64 lowbit(int x)
{
    return (-x)&x;
}
inline void update(__int64 a[], int x, __int64 c)
{
    while(x <= maxn)
    {
        a[x] += c;
        x += lowbit(x);
    }
}

inline __int64 getSum(__int64 a[], int x)
{
    __int64 sum0 = 0;
    while(x)
    {
        sum0 += a[x];
        x -= lowbit(x);
    }
    return sum0;
}
//根据公式Sum[x] = SUM(A[i], i=1...x)+(x+1)*SUM(delta[i],i=1...x)-SUM(i*delta[i],i=1...x)求Sum[x]
__int64 Sum(__int64 t1[], __int64 t2[], int x)
{
    __int64 res = sum[x];
    res += (x+1)*getSum(t1, x);
    res -= getSum(t2, x);
    return res;
}
int main()
{
    int  n, q, tmp;
    mem(t1, 0);
    mem(t2, 0);
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &tmp);
        sum[i] = sum[i-1] + tmp;
    }
    while(q--)
    {
        __int64 suma, sumb;
        char ch;
        int a, b, c;
        getchar();
        scanf("%c", &ch);
        if(ch == 'Q')
        {
            scanf("%d%d", &a, &b);
            suma = Sum(t1, t2, a-1);
            sumb = Sum(t1, t2, b);
            printf("%I64d\n", sumb - suma);
        }
        else
        {
            scanf("%d%d%d", &a, &b, &c);

            update(t1, a, c);//更新SUM(delta[i],i=1...x)中的delta[a]  
            update(t2, a, a*c);//更新SUM(i*delta[i],i=1...x)中的delta[a]  
            //这两个update后,区间A[a...n]每个数都增加了c。  
            update(t1, b+1, -c);//这两个update后,区间A[b+1...n]每个数都减少了c,完成对区间A[a...b]的更新  
            update(t2, b+1, -(b+1)*c);
        }
    }
    return 0;
}


 

 还是要学习线段树/树状数组.....

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值