// 6884K 2032MS G++
#include "cstdio"
#include "cstring"
#include "iostream"
using namespace std;
#define MAX 100010
struct TreeNode {
long left;
long right;
long long sum;
long long lazyAdd;
};
TreeNode tree[100010<<2];
long treeSize;
long opNum;
void buildTree(long pos, long begin, long end) {
TreeNode & curNode = tree[pos];
curNode.left = begin;
curNode.right = end;
curNode.lazyAdd = 0;
if (begin == end) {
return;
} else {
long mid = (begin + end)>>1;
buildTree(pos<<1, begin, mid);
buildTree(pos<<1|1, mid+1, end);
}
}
void pushUp(long pos) {
if (pos == 1) {
return;
}
long parentPos = pos>>1;
TreeNode & leftNode = tree[parentPos<<1];
TreeNode & rightNode = tree[parentPos<<1|1];
TreeNode & curNode = tree[parentPos];
curNode.sum = leftNode.sum + rightNode.sum;
// printf("pushUp %d %d %lld\n", curNode.left, curNode.right, curNode.sum);
}
void updateSingleNumber(long treePos, long pos, long long val) {
TreeNode & curNode = tree[treePos];
long left = curNode.left;
long right = curNode.right;
if (left == right && left == pos) {
curNode.sum = val;
} else {
long mid = (left + right)>>1;
if (pos <= mid) {
updateSingleNumber(treePos<<1, pos, val);
} else {
updateSingleNumber(treePos<<1|1, pos, val);
}
}
pushUp(treePos);
}
void pushDown(long pos) {
TreeNode & curNode = tree[pos];
long long curLazyAdd = curNode.lazyAdd;
if (curLazyAdd != 0) {
TreeNode & leftNode = tree[pos<<1];
TreeNode & rightNode = tree[pos<<1|1];
leftNode.lazyAdd += curLazyAdd;
rightNode.lazyAdd += curLazyAdd;
leftNode.sum += curLazyAdd * (leftNode.right - leftNode.left + 1);
rightNode.sum += curLazyAdd * (rightNode.right - rightNode.left + 1);
// printf("pushDown %d %d %lld\n", leftNode.left, leftNode.right, leftNode.sum);
// printf("pushDown %d %d %lld\n", rightNode.left, rightNode.right, rightNode.sum);
curNode.lazyAdd = 0;
}
}
long long querySum(long pos, long rangeLeft, long rangeRight) {
// printf("querySum %d %d\n", rangeLeft, rangeRight);
TreeNode & curNode = tree[pos];
long left = curNode.left;
long right = curNode.right;
if ((rangeLeft <= left) && (right <= rangeRight)) {
// printf("querySum1 %d %d %d %d %lld\n", left, right, rangeLeft, rangeRight,curNode.sum);
return curNode.sum;
}
pushDown(pos);
long mid = (left + right)>>1;
if (rangeRight <= mid) {
long long res = querySum(pos<<1, rangeLeft, rangeRight);
// printf("querySum2 %d %d %d %d %lld\n", left, right, rangeLeft, rangeRight, res);
return res;
} else if (rangeLeft<= mid && rangeRight > mid) {
long long res = querySum(pos<<1, rangeLeft, mid) +
querySum(pos<<1|1, mid+1, rangeRight);
// printf("querySum3 %d %d %d %d %lld\n", left, right, rangeLeft, rangeRight, res);
return res;
} else if (rangeLeft > mid) {
long long res = querySum(pos<<1|1, rangeLeft, rangeRight);
// printf("querySum4 %d %d %d %d %lld\n", left, right, rangeLeft, rangeRight, res);
return res;
}
}
void updateRange(long pos, long rangeLeft, long rangeRight, long long addVal) {
if (!addVal) {
return;
}
TreeNode & curNode = tree[pos];
long left = curNode.left;
long right = curNode.right;
// long long curLazyAdd = curNode.lazyAdd;
if ((rangeLeft <= left) && (right <= rangeRight)) {
curNode.sum += addVal * (right - left +1);
curNode.lazyAdd += addVal;
// printf("A\n");
pushUp(pos);
return;
}
// printf("B\n");
pushDown(pos);
long mid = (left + right)>>1;
if (rangeRight <= mid) {
updateRange(pos<<1, rangeLeft, rangeRight, addVal);
} else if (rangeLeft <= mid) {
updateRange(pos<<1, rangeLeft, mid, addVal);
updateRange(pos<<1|1, mid + 1, rangeRight, addVal);
} else if (rangeLeft > mid) {
updateRange(pos<<1|1, rangeLeft, rangeRight, addVal);
}
pushUp(pos);
}
int main() {
while(scanf("%ld %ld", &treeSize, &opNum) != EOF) {
buildTree(1, 1, treeSize);
for (int i = 1; i <= treeSize; i++) {
long long val;
scanf("%lld", &val);
updateSingleNumber(1, i, val);
}
char tmp;
// scanf("%c", &tmp);
for (int i = 1; i <= opNum; i++) {
char s[5];
scanf("%s",s);
if (s[0] == 'C') {
long left, right;
long long add;
scanf("%ld%ld%lld", &left, &right, &add);
updateRange(1, left, right, add);
} else if (s[0] == 'Q') {
long left, right;
scanf("%ld%ld", &left, &right);
// printf("%lld\n", querySum(1, left, right));
cout<<querySum(1, left, right)<<endl;
}
}
}
}
sigh, 线段树区间操作经典题, 此题的AC率低,当时看到,就大概估计是错误的人很多都是数值类型引起的,结果到了自己,也因为这个WA了几次...., lazyAdd的某个中间值没取成long long的64位。
正好刚学完线段树的区间操作和lazytag, 正好在这道题上一用,基本只要心里比较清楚,就能写出正确的code来,中规中矩,
首先就是构造线段树,每个区间节点除了left 和 right外,还要维护两个变量:
该区间的所有数的和 sum 以及 lazyAdd(标记被lazy在此区间节点,没有下发到子区间的要加的数的和)。
一开始要先把所有的初始数值搞进线段树去,直接搞了一个专门的函数,不断递归向下,直到找到正确的位置(一个线段点)放置,然后自下而上更新父区间节点的sum,
然后就是读取若干条指令集了,判断是求某个区间的和 还是 对某个区间的所有数都加上某个数
如果是求某个区间的和,很简单,只需不断根据当前节点的区间和 要求区间的交并情况来递归的对子区间进行求即可,一个很关键的点是:
如果当前在某个区间[l. r], 如果要求的区间和[l1, r2] 不能完全将此区间覆盖, 那么要进行pushDown(将父区间的lazyAdd累加到子区间的lazyAdd,然后父区间的lazyAdd变为0代表在此区间没有被lazy的操作,同时还要对子区间的sum也进行更新,加上lazyAdd * 区间长度,其实就是之前加操作的执行)来将当前区间的lazyAdd下发到其子区间以后,才能继续递归的根据区间交并情况递归向下,还要注意,因为 求区间和这个操作其实没有修改线段树的值,因此不需要pushUp来更新父区间(有些题在这种情况下也需要)
如果是对某个区间进行批量加 S,那么也是根据区间情况不断向下递归求,注意这里要使用lazyTag来提高效率,
如果当前处理到了某个区间[l, r] , 而要批量加的区间是[l1, r1], 如果 [l1, r1]能完全覆盖 [l, r], 那么就不需要再向下递归了,直接先对该区间的sum进行add(S* 区间数的个数), 然后对其lazyTag进行累加即可, 否则根据 [l, r] 在 [l1, r1]的分布情况进行继续的递归处理,注意的是,在每次递归更新某个区间的最后,要调用pushUp来用新的子区间的sum更新父区间的sum,这样才能保证 这次的改变体现在每个被影响的区间上.