HDU 4348 To the moon

传送门

  • 区间([l,r])加上(d)并更新版本
  • 查询当前版本([l,r])区间的和
  • 查询(t)版本的([l,r])的区间和
  • 回溯到历史版本(t)

可持久化,就用可持久化线段树去操作。
主席树其实不止可以用于权值线段树,当使用线段树时,也可以操作的。
但是如果用线段树的区间操作里面,使用lazy标记去进行区间修改,是不对的。

标记永久化:标记永久化,顾名思义,指标记一旦被打上,就不再下传或清空。而是在询问的过程中计算每个遇到结点对当前询问的影响。

因为对于主席树,每次修改操作我们在之前基础上建一棵新树,但是他们的一些儿子是共用的,如果直接用线段树的lazy标记pushdown一下,之前的版本也会受到影响。而我们的想法就是只修改当前版本的标记。标记不用pushdown,自然也不用pushup(开始建树的时候,可能要pushup)

其实永久性标记相当于是在每次修改,都会进行更新操作,但也加入了一个lazy标记,而在区间查询时,不断递归,同时也需要更新一个权值,代表我要找的区间需要增加的标记值。

标记永久化与惰性标记的最大区别在于是否去向下传递。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
int a[N];
struct Chairman_tree{
    int lc[N << 5], rc[N << 5], rt[N], tot;
    ll sum[N << 5], lazy[N << 5];
    void build(int &now, int l, int r){
        now = ++tot;
        lazy[now] = lc[now] = rc[now] = 0;
        if(l == r) {
            sum[now] = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(lc[now], l, mid); build(rc[now], mid + 1, r);
        sum[now] = sum[lc[now]] + sum[rc[now]];
    }
    void Update(int &now, int pre, int L, int R, int l, int r, ll val){
        now = ++tot;
        lc[now] = lc[pre], rc[now] = rc[pre], lazy[now] = lazy[pre];
        sum[now] = sum[pre] + (min(R, r) - max(L, l) + 1) * val;
        if(l <= L && R <= r) {
            lazy[now] += val;
            return;
        }
        int mid = (L + R) >> 1;
        if(l <= mid) Update(lc[now], lc[pre], L, mid, l, r, val);
        if(r > mid) Update(rc[now], rc[pre], mid + 1, R, l, r, val);
    }
    ll Query(int now, int L, int R, int l, int r, ll cc){
        if(l <= L && R <= r) return sum[now] + cc * (R - L + 1);
        int mid = (L + R) >> 1;
        ll ans = 0;
        if(l <= mid) ans += Query(lc[now], L, mid, l, r, cc + lazy[now]);
        if(r > mid) ans += Query(rc[now], mid + 1, R, l, r, cc + lazy[now]);
        return ans;
    }
} ct;
int main(){
    int n, m;
    while(~scanf("%d%d", &n, &m)){
        ct.tot = 0;
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        ct.build(ct.rt[0], 1, n);
        int nowhis = 0;
        for(int i = 1; i <= m; i++) {
            char op[10]; int l, r, add, his;
            scanf("%s", op);
            if(op[0] == 'Q') {
                scanf("%d%d", &l, &r);
                printf("%lld
", ct.Query(ct.rt[nowhis], 1, n, l, r, 0));
            }
            if(op[0] == 'C') {
                scanf("%d%d%d", &l, &r, &add);
                nowhis++;
                ct.Update(ct.rt[nowhis], ct.rt[nowhis - 1], 1, n, l, r, add);
            }
            if(op[0] == 'H') {
                scanf("%d%d%d", &l, &r, &his);
                printf("%lld
", ct.Query(ct.rt[his], 1, n, l, r, 0));
            }
            if(op[0] == 'B') {
                scanf("%d", &nowhis);
            }
        }
    }
    return 0;
}
I‘m Stein, welcome to my blog
原文地址:https://www.cnblogs.com/Emcikem/p/14545281.html