题目链接:[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; }