题意:
给一个数组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; }