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;
}
原文地址:https://www.cnblogs.com/KirinSB/p/10776423.html