• 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
  • 相关阅读:
    基于bootstrap分页
    encache学习教程
    java异常和spring事务注解
    JSP自定义标签开发入门
    spring junit
    vs与数据库连接查询
    winfrom文本文档打开
    面向对象 封装
    面向对象 概念
    DW 游记代码
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14545281.html
Copyright © 2020-2023  润新知