题目链接:[POJ 3468]A Simple Problem with Integers[树状数组区间更新+求和]
题意分析:
对特定的连续区间进行更新值并求出特定区间的和。
解题思路:
使用树状数组进行区间更新,最主要的思想就是将区间的改变量保存下来。
详细解答戳这里:http://kenby.iteye.com/blog/962159
说一说对最终 ans[x] = segma(org[i]) + (x+1)*segma(delta[i]) - segma(delta[i]*i),1 <= i <= x 的理解:
为什么是segma(delta[i]*(x - i + 1))对最终求和有影响:因为delta[i]的定义是:对区间[i,n]的共同增量。假设题目目前只说区间[2,6]加4(假设整个区间[1,10]),那么此时delta[2] = 4, delta[6] = -4。虽然根据定义delta[5](即5到n的共同增量)应该为4,但是我们只更新与区间端点有关的那部分,并不会更新这些无关部分,所以最终算整个影响时,是把1到x的delta[i]和相加。
个人感受:
求和那段理解了好久Orz
具体代码如下:
#include<iostream>
#include<cstdio>
#define lowbit(x) (x & (-x))
#define ll long long
using namespace std;
const int MAXN = 1e5 + 111;
int n;
ll sum[MAXN], c1[MAXN], c2[MAXN], a[MAXN];
ll query(ll *array, int x) // 求前x项的和
{
ll ret = 0;
while (x > 0)
{
ret += array[x];
x -= lowbit(x);
}
return ret;
}
void add(ll *array, int x, ll val) // 更新所有影响到的区间
{
while (x <= n)
{
array[x] += val;
x += lowbit(x);
}
}
int main()
{
int q, l, r, d; scanf("%d%d", &n, &q);
for (int i = 1; i <= n; ++i)
{
scanf("%lld", a + i);
sum[i] = a[i] + sum[i - 1];
}
char op[2];
while (q --)
{
scanf("%s%d%d", op, &l, &r);
// c1[i] = delta[i]; c2[i] = i * delta[i];
// ans[x] = segma(org[i]) + (x+1)*segma(delta[i]) - segma(delta[i]*i),1 <= i <= x
if (op[0] == 'Q')
{
--l;
ll ans = sum[r] - sum[l];
ans += (r + 1)*query(c1, r) - (l + 1)*query(c1, l);
ans -= query(c2, r) - query(c2, l);
printf("%lld\n", ans);
}
else
{
scanf("%d", &d);
add(c1, l, d);
add(c1, r + 1, -d);
add(c2, l, d * l);
add(c2, r + 1, -d * (r + 1));
}
}
return 0;
}