zoukankan      html  css  js  c++  java
  • HDU 4348 To the moon(主席树 区间更新)题解

    题意:

    给一个数组A[1] ~ A[n],有4种操作:

    Q l r询问l r区间和

    C l r v给l r区间每个数加v

    H l r t询问第t步操作的时候l r区间和

    B t返回到第t步操作

    思路:

    用主席树维护常规的线段树。我们之前已经知道了主席树单点更新,只要新增一条链就ok了,区间更新也有点差不多。我们每次要更新都用一个lazy标记,但是显然我们不能去更新那些已经存在的区间,那么我们就新建出所有要更新的区间。因为可持久化线段树有些结点不是自己的,所以我们不能直接简单的push up和push down,那么我们在对区间加v的时候处理为:如果这个区间完全是新建的(L <= l && R >= r),那么我直接加lazy标记就好,不是的话就直接更新要更新的区间的那部分 T[now].sum += (min(R, r) - max(L, l) + 1) * v ,然后继续往下更新。我在查询的时候,遇到lazy都要直接加上,因为我这个lazy是不往下传的,所以你往下走的时候要先加上指定的区间的lazy。

    代码:

    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include <iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 1e5 + 10;
    const int M = maxn * 30;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1000000007;
    int a[maxn], root[maxn], tot;
    int n, m;
    struct node{
        int lson, rson;
        ll sum, lazy;
    }T[maxn * 40];
    void init(){
        tot = 0;
    }
    void pushUp(int rt){
        T[rt].sum = T[T[rt].lson].sum + T[T[rt].rson].sum;
    }
    void build(int l, int r, int &rt){
        rt = ++tot;
        T[rt].lazy = T[rt].sum = 0;
        if(l == r){
            T[rt].sum = a[l];
            return;
        }
        int m = (l + r) >> 1;
        build(l, m,T[rt].lson);
        build(m + 1, r, T[rt].rson);
        pushUp(rt);
    }
    void update(int l, int r, int L, int R, int &now, int pre, ll v){
        T[++tot] = T[pre], now = tot;
        T[now].sum += (min(R, r) - max(L, l) + 1) * v;
        if(L <= l && R >= r){
            T[now].lazy += v;
            return;
        }
        int m = (l + r) >> 1;
        if(L <= m)
            update(l, m, L, R, T[now].lson, T[pre].lson, v);
        if(R > m)
            update(m + 1, r, L, R, T[now].rson, T[pre].rson, v);
    }
    ll query(int l, int r, int L, int R, int rt){
        if(L <= l && R >= r){
            return T[rt].sum;
        }
        int m = (l + r) >> 1;
        ll ans = (min(R, r) - max(L, l) + 1) * T[rt].lazy;
        if(L <= m)
            ans += query(l, m, L, R, T[rt].lson);
        if(R > m)
            ans += query(m + 1, r, L, R, T[rt].rson);
        return ans;
    }
    int main(){
        while(~scanf("%d%d", &n, &m)){
            init();
            for(int i = 1; i <= n; i++)
                scanf("%d", &a[i]);
            int time = 0;
            build(1, n, root[time]);
            while(m--){
                char o[3];
                int l, r, v;
                scanf("%s", o);
                if(o[0] == 'C'){
                    scanf("%d%d%d", &l, &r, &v);
                    ++time;
                    update(1, n, l, r, root[time], root[time - 1], v);
                }
                else if(o[0] == 'Q'){
                    scanf("%d%d", &l, &r);
                    printf("%lld
    ", query(1, n, l, r, root[time]));
                }
                else if(o[0] == 'H'){
                        scanf("%d%d%d", &l, &r, &v);
                        printf("%lld
    ", query(1, n, l, r, root[v]));
                }
                else{
                    scanf("%d", &v);
                    time = v;
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    bash脚本编程之数组和字符串处理
    Linux启动流程简介以及各启动阶段失败的恢复方法
    Linux路由表的重要性以及配置
    Linux终端和伪终端简述
    Linux九阴真经之无影剑残卷9(Shell脚本编程进阶)
    Linux九阴真经之无影剑残卷8(计划任务)
    Linux九阴真经之无影剑残卷7(进程管理)
    Linux九阴真经之无影剑残卷5(Linux静态路由的实现)
    Linux九阴真经之无影剑残卷4(创建虚拟内存--swap)
    Linux九阴真经之无影剑残卷3(将home目录搬到新分区)
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10776423.html
Copyright © 2011-2022 走看看