线段树lazy标记
来源:互联网 发布:蜂云网络 编辑:程序博客网 时间:2024/05/16 03:39
http://poj.org/problem?id=3468
线段树的核心就是build,query,update,其中update又分为单点更新和区间更新,在区间更新的过程中,如果一路更新到底可能会造成时间消耗很大,而后续的询问并没有用到,这样就造成了资源的浪费,lazy就在这里发挥作用。
在update的过程中如果找到了update的区间(比如2-5),那就把2-5的区间的sum值修改就好了,如果按照正常的思维,这时应该把2-5所在的子区间也全部更新,但是在后续的query中可能并没有用到以下的这些更新值,那么就先不用更新,先用lazy把它存起来。
这样的后果就是在下次询问(query)的过程中,如果有遇到lazy值不为0,也就是有一些更新还没有完成的情况时,就需要把lazy值给释放出来,向下更新一下。
另外在线段树中,区间更新和单点更新得区别就在于update函数,单点更新,位置只能位于一个区间内,而区间更新,这个区间极有可能位于跨度两个区间,这需要注意。
还有写线段树时,pushup和pushdown函数是刚学的,觉得可以让程序更简单易懂,现在渐渐感觉到每个人写程序的风格都是不一样的,一个比较好的算法实现流程可能差不多,但是自己代码的模板是不一样的。
下面的链接是我学习线段树很有力的帮助,博主代码风格简洁,整理的例题也很到位,很喜欢~虽然有些代码还是有些问题……但是适合像我这样萌新(菜鸟),hhh,分享给大家。
http://blog.csdn.net/metalseed/article/details/8039326
POJ3468AC代码
#include<iostream>using namespace std;const int maxn = 100005;struct Tree{ int left, right; long long sum; long long lazy;}tree[maxn*4];long long a[maxn];void pushup(int root){ tree[root].sum = tree[root * 2].sum + tree[root * 2 + 1].sum;}//向上更新父节点void pushdown(int root, int m){ if (tree[root].lazy) { tree[root * 2].lazy += tree[root].lazy; tree[root * 2 + 1].lazy += tree[root].lazy; tree[root * 2].sum += tree[root].lazy*(m - (m / 2)); tree[root * 2 + 1].sum += tree[root].lazy*(m / 2); tree[root].lazy = 0; }}//向下更新,lazy关键void build(int root, int start, int end){ tree[root].lazy = 0; tree[root].left = start; tree[root].right = end; if (start == end) { tree[root].sum = a[start]; return; } int mid = (start + end) / 2; build(root * 2, start, mid); build(root * 2 + 1, mid + 1, end); pushup(root);}void update(int root,int start,int end,int value){ if (start <= tree[root].left&&tree[root].right <= end) //区间的更新,这句话的意思与start == tree[root].left&&tree[root].right == end相同 { tree[root].lazy += value; tree[root].sum += (long long)value*(tree[root].right - tree[root].left + 1); return; //lazy关键 } /*if (tree[root].left == tree[root].right) return;*/ pushdown(root, tree[root].right - tree[root].left + 1); int mid = (tree[root].right + tree[root].left) / 2; if (end <= mid) update(root * 2, start, end, value); else if (start >= mid + 1) update(root * 2 + 1, start, end, value); else { update(root * 2, start, mid, value); update(root * 2 + 1, mid + 1, end, value); }//区间更新与单点更新的不同就是多了这个else pushup(root);}long long query(int root,int start,int end){ if (start <= tree[root].left&&tree[root].right <= end) return tree[root].sum; pushdown(root, tree[root].right - tree[root].left + 1); //lazy,然后现在需要调用这个值,就要更新 int mid= (tree[root].right + tree[root].left) / 2; long long reu = 0; if (end <= mid) reu += query(root * 2, start, end); else if (start >= mid + 1) reu += query(root * 2 + 1, start, end); else reu = query(root * 2, start, mid) + query(root * 2 + 1, mid+1, end); return reu;}int main(){ int n, q; while (cin >> n >> q) { int i; for (i = 1; i <= n; i++) cin >> a[i]; build(1, 1, n); while (q--) { char order; int a, b, c; cin >> order; if (order == 'Q') { cin >> a >> b; cout << query(1, a, b) << endl; } else if(order=='C') { cin >> a >> b >> c; update(1, a, b, c); } } } return 0;}
阅读全文
0 0
- 线段树lazy标记
- 线段树lazy标记??Hdu4902
- Transformation(线段树 + lazy 标记)
- 线段树lazy标记2
- poj 3225 线段树注意lazy标记
- POJ 3468 线段树+lazy标记
- bzoj 1798 线段树 双lazy标记
- hdu 4578 线段树lazy标记
- 线段树区间修改 lazy标记 大法
- 线段树lazy标记1血题
- POJ3468 线段树 + Lazy Tag (延迟标记)
- poj1436(线段树lazy标记)
- POJ 3225 线段树+lazy标记
- 还教室(线段树lazy标记)
- 线段树lazy标记入门笔记
- poj 3468 线段树 lazy标记模板
- 线段树lazy标记永久化
- 线段树模板(lazy标记)ZOJ 3686
- HDU 5699 货物运输
- 去除inline-block元素间间距的N种方法
- android 国内中文资源
- 2015 UESTC Training for Dynamic Programming 男神的礼物(区间dp)
- [HDU 1176] 免费馅饼 [ DP + 思维 ]
- 线段树lazy标记
- Python--uiautomator特殊情况
- 间接直接通过list链表中的位置获取数据
- java.net.UnknownHostException: XXX.COM: 未知的名称或服务
- FactoryBean的理解
- 不相交集ADT详解
- js截取url的参数,?号后面参数的几种方法
- iOS如何查看手机沙盒中的文件(GT生成文件)
- Android APP 简单高效的禁用横竖屏切换