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,这样才能保证 这次的改变体现在每个被影响的区间上.
- poj 3468
- POJ 3468
- poj 3468
- poj 3468
- poj 3468
- poj 3468
- poj 3468
- POJ 3468
- POJ 3468
- POJ 3468
- POJ 3468
- POJ 3468
- poj 3468
- poj-3468
- POJ 3468
- POJ 3468
- POJ-3468
- poj 3468
- 为数字键盘添加自定义按钮的方法
- 2014多校5---1002 HDU4912 ( Paths on the tree ) LCA+贪心+bfs/dfs
- ZOJ1649
- 数字图像处理之归一化方法
- 用bash 写的CVS版本控制脚本
- poj-3468
- iOS开发点滴-CocoaPods安装和使用教程
- android 浅探打包安装APK
- 【HDU】1890 Robotic Sort 翻转区间【splay】
- 关于IDEA 的常用操作(持续更新)
- ZOJ1608
- 又优化了一下 Android ListView 异步加载图片
- Mina3.0的UML类图
- STM32学习笔记——学前准备