题目:题目链接
题意:
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.The second line contains N numbers,
the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.Each of the next Q lines
represents an operation."C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+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;
}
还是要学习线段树/树状数组.....