poj-3468

来源:互联网 发布:中国十大网络主播 编辑:程序博客网 时间:2024/05/16 09:11
// 6884K    2032MS  G++#include "cstdio"#include "cstring"#include "iostream"using namespace std;#define MAX 100010struct 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,这样才能保证 这次的改变体现在每个被影响的区间上. 

0 0