线段树(成段更新 关于延迟标记) poj3468
2011-12-18 21:46
387 查看
延迟标记:当我们在对某个节点rt进行更新时,先不向其子节点更新(如果向其子节点更新,更新到叶子节点,那么更新操作的时间复杂度就达到了O(n)),
当我们要用到该节点的后裔的时候,再将该延迟标记向下移动,这样更新操作就仍为O(logn)的时间复杂度。
当我们要用到该节点的后裔的时候,再将该延迟标记向下移动,这样更新操作就仍为O(logn)的时间复杂度。
#include <iostream> #include <cstdio> using namespace std; #define N 100005 __int64 sum[N << 2]; __int64 mark[N << 2]; inline void pushUp (int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void pushDown (int rt, int len) { if (mark[rt]) { //因为rt的儿子节点可能被多次延迟标记,并且rt的儿子节点的延迟标记没有向rt的孙子节点移动,所以用“+=” mark[rt << 1] += mark[rt]; mark[rt << 1 | 1] += mark[rt]; /*此处用mark[rt]乘以区间长度,不是mark[rt<<1], 因为rt的儿子节点如果被多次标记,之前被标记时, 就已经对sum[rt<<1]更新过了。 */ sum[rt << 1] += mark[rt] * (len - (len >> 1)); sum[rt << 1 | 1] += mark[rt] * (len >> 1); mark[rt] = 0; //将标记向儿子节点移动后,父节点的延迟标记去掉 } } void build (int l, int r, int rt) { mark[rt] = 0; if (l == r) { scanf ("%I64d", &sum[rt]); return; } int m = (l + r) >> 1; build (l, m, rt << 1); build (m + 1, r, rt << 1 | 1); pushUp (rt); } void update (int L, int R, __int64 c, int l, int r, int rt) { if (l >= L && r <= R) { mark[rt] += c; sum[rt] += c * (r - l + 1); return; } /*当要对被延迟标记过的这段区间的儿子节点进行更新时,先要将延迟标记向儿子节点移动 当然,如果一直没有对该段的儿子节点更新,延迟标记就不需要向儿子节点移动,这样就使 更新操作的时间复杂度仍为O(logn),也是使用延迟标记的原因。 */ pushDown(rt, r - l + 1); int m = (l + r) >> 1; if (m >= L) update (L, R, c, l, m, rt << 1); if (m < R) update (L, R, c, m + 1, r, rt << 1 | 1); pushUp (rt); } __int64 query (int L, int R, int l, int r, int rt) { if (l >= L && r <= R) return sum[rt]; //要取rt子节点的值时,也要先把rt的延迟标记向下移动 pushDown(rt, r - l + 1); int m = (l + r) >> 1; __int64 ret = 0; if (m >= L) ret += query (L, R, l, m, rt << 1); if (m < R) ret += query (L, R, m + 1, r, rt << 1 | 1); return ret; } int main() { int n, q, a, b; __int64 c; char op; scanf ("%d %d", &n, &q); build (1, n, 1); while (q--) { getchar(); scanf ("%c %d %d", &op, &a, &b); if (op == 'Q') printf ("%I64d\n", query (a, b, 1, n, 1)); else { scanf ("%I64d", &c); update (a, b, c, 1, n, 1); } } return 0; }
相关文章推荐
- 关于线段树懒惰标记的理解,成段更新(poj 3468为例)
- poj3468 A Simple Problem with Integers 线段树延迟标记区间更新区间求和
- hdu 1698 Just a Hook(线段树成段更新+延迟标记).
- POJ3468 线段树 + Lazy Tag (延迟标记)
- FZU1608(线段树成段更新,区间求和pushdown延迟标记结构体版)
- POJ3468 线段树(区间更新,区间求和,延迟标记)
- poj3468-A Simple Problem with Integers 线段树成段增减,区域求和(延迟标记)
- POJ 3468 线段树成段更新区间求和 + 延迟标记详解 A Simple Problem with Integers
- poj 1436 Horizontally Visible Segments(线段树)(第二部分成段更新 不需要延迟标记 )
- 线段树成段更新+延迟标记法-杭电3911
- 【hdu】 Just a Hook (线段树 -成段更新,延迟标记)
- poj 3468 A Simple Problem with Integers(线段树成段更新,延迟标记,Lazy)
- poj3468---线段树----区间单点更新、区间和查询----有延迟标记
- 浅析__线段树延迟标记
- 线段树专题#4_蒟蒻训练历程记录_HDU1698_ 延迟标记、区间更新
- Poj3468(线段树延迟更新)
- 【线段树成段更新成段查询模板】【POJ3468】A Simple Problem with Integerst
- 线段树成段更新裸题POJ3468
- 【线段树】A Simple Problem with Integers(区间查询和延迟标记)
- hdu 1698 poj 3468 线段树 成段更新(lazy标记)