HDU 4348(主席树 标记永久化)
题面一看就是裸的数据结构题,而且一看就知道是主席树。。。
一共四种操作:1:把区间[l, r]的数都加上d,并且更新时间。2:查询当前时间的区间和。3:查询历史时间的区间和。4:时光倒流到某个时间。
正常来说,主席树比较难支持区间操作,但是我们可以用标记永久化的方法去实现区间操作。标记永久化和懒标记下放不一样,标记永久化是这样操作的:对所有和标记区间相关的区间,直接加上这次操作的影响,如果这个区间被标记区间完全覆盖,就打上标记。查询的时候,需要把访问沿途的所有的区间的标记算上。
代码:
#include <bits/stdc++.h> #define LL long long using namespace std; const int maxn = 100010; struct SegementTree { int ls, rs; long long sum, flag; }; SegementTree tr[maxn * 200]; int tot, a[maxn], root[maxn], Time; void pushup(int now) { tr[now].sum = tr[tr[now].ls].sum + tr[tr[now].rs].sum; } void build(int now, int l, int r) { tr[now].ls = tr[now].rs = tr[now].sum = tr[now].flag = 0; if(l == r) { tr[now].sum = a[l]; tr[now].flag = 0; return; } int mid = (l + r) >> 1; tr[now].ls = ++tot; build(tot, l, mid); tr[now].rs = ++tot; build(tot, mid + 1, r); pushup(now); } void insert(int lnow, int rnow, int l, int r, int ql, int qr, LL val) { tr[rnow] = tr[lnow];tr[rnow].sum += val * (qr - ql + 1); if(l == ql && r == qr) { tr[rnow].flag += val; return; } int mid = (l + r) >> 1; if(qr <= mid) { tr[rnow].ls = ++tot; insert(tr[lnow].ls, tot, l, mid, ql, qr, val); } else if(ql > mid) { tr[rnow].rs = ++tot; insert(tr[lnow].rs, tot, mid + 1, r, ql, qr, val); } else { tr[rnow].ls = ++tot; insert(tr[lnow].ls, tot, l, mid, ql, mid, val); tr[rnow].rs = ++tot; insert(tr[lnow].rs, tot, mid + 1, r, mid + 1, qr, val); } // pushup(rnow); } LL query(int now, int l, int r, int ql ,int qr) { if(l >= ql && r <= qr) { return tr[now].sum; } int mid = (l + r) >> 1; LL ans = tr[now].flag * (qr - ql + 1); if(qr <= mid) ans += query(tr[now].ls, l, mid, ql, qr); else if(ql > mid) ans += query(tr[now].rs, mid + 1, r, ql, qr); else { ans += query(tr[now].ls, l, mid, ql, mid); ans += query(tr[now].rs, mid + 1, r, mid + 1, qr); } return ans; } char s[10]; int main() { int x, y, z, n, m, kase = 0; while(~scanf("%d%d", &n, &m)) { tot = 0, Time = 0; kase++; if(kase > 1) printf("\n"); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } root[0] = ++tot; build(tot, 1, n); while(m--) { scanf("%s", s + 1); if(s[1] == 'C') { scanf("%d%d%d", &x, &y, &z); root[++Time] = ++tot; insert(root[Time - 1], root[Time], 1, n, x, y, z); } else if(s[1] == 'Q') { scanf("%d%d", &x, &y); printf("%lld\n", query(root[Time], 1, n, x, y)); } else if(s[1] == 'H') { scanf("%d%d%d", &x, &y, &z); printf("%lld\n", query(root[z], 1, n, x, y)); } else { scanf("%d", &x); tot = root[x + 1] - 1; Time = x; } } } }