线段树lazy poj3468
虽然这几天睡眠质量不太好,但是这几天还是很happy的。
先说一下线段树。线段树是一个高效的数据结构,上一篇文章已经介绍过。具体参考:http://www.cnblogs.com/gufeiyang/p/4106794.html
今天学习了带lazy的线段树。
当做区间修改的时候如果线段树递归每次修改都进行到每一个位置上去的话, 那么效率是非常低的,往往还不如直接暴力。
于是乎就有这么这么一种懒惰的做法,当修改的时候如果修改的是一个整块,那么就只对这个整块修改,整块再细分的内容先不做修改,只有当用到这个块底层的时候再修改。这其实是一种懒惰的做法。但这种做法非常实用,并且特别高效,复杂度依然为O(log)级别的。
poj 3468题意:给出一个数组,长度为n,q个操作。 'C'操作 对区间[a,b]中的每个数字都加c. ‘Q’操作,询问区间[a,b]的所有数字之和。
思路:线段树lazy做法。
代码风格参考notonlysuccess的代码风格。 这里注意,当修改区间的时候不单单是修改lazy,是增加lazy的值。
AC代码:
#include <iostream> #include <cstdio> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; typedef long long LL; const int maxn = 100005; const LL INF = 1LL<<60; LL sum[maxn*4]; LL ele[maxn]; LL lazy[maxn*4]; int n, q; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void build(int l, int r, int rt) { lazy[rt] = 0; sum[rt] = 0; if(l == r) { sum[rt] = ele[l]; return ; } int m = (l+r)>>1; build(lson); build(rson); PushUp(rt); } void PushDown(int rt, int m) { if(lazy[rt] != 0) { lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt]; sum[rt<<1] += (m-(m>>1)) * lazy[rt]; sum[rt<<1|1] += (m>>1) * lazy[rt]; lazy[rt] = 0; } } void add(int L, int R, LL C, int l, int r, int rt) { if(L<=l && r<=R) { sum[rt] += C*(r-l+1); lazy[rt] += C; return ; } PushDown(rt, r-l+1); int m = (l+r)>>1; if(m >= L) add(L, R, C, lson); if(m < R) add(L, R, C, rson); PushUp(rt); } LL query(int L, int R, int l, int r, int rt) { if(L<=l && r<=R) { return sum[rt]; } PushDown(rt, r-l+1); int m = (l+r)>>1; LL ret = 0; if(m>=L) ret += query(L, R, lson); if(m<R) ret += query(L, R, rson); PushUp(rt); return ret; } int main() { while(scanf("%d%d", &n, &q) != EOF) { for(int i=1; i<=n; i++) { scanf("%lld", &ele[i]); } build(1, n, 1); char str[10]; int a, b; LL c; while(q--) { scanf("%s%d%d", str, &a, &b); if(str[0] == 'C') { scanf("%lld", &c); add(a, b, c, 1, n, 1); } else if(str[0] == 'Q') { LL ans = query(a, b, 1, n, 1); printf("%lld\n", ans); } } } return 0; }

浙公网安备 33010602011771号