SP11470 TTM - To the moon
阿新 • • 發佈:2020-09-07
題意
一個長度為 \(n\) 的陣列,\(4\) 種操作 :
C l r d
:區間 \([l,r]\) 中的數都加 \(d\),同時當前的時間戳加 \(1\)。Q l r
:查詢當前時間戳區間 \([l,r]\)中所有數的和 。H l r t
:查詢時間戳 \(t\) 區間 \([l,r]\) 的和 。B t
:將當前時間戳置為 \(t\)。
簡化題意:給定一個長度為 \(n\) 的陣列,要求支援區間修改、查詢某版本某個區間的和、版本回溯。
思路
可持久化線段樹 + 標記永久化
這玩意兒不能叫做主席樹 \(qwq\)
題意簡述一下就是帶修改的可持久化線段樹。
普通的線段樹在區間修改時可以打標記,用到子節點的時候再進行 pushdown
每次執行修改操作時,仍然對被修改區間覆蓋的節點打上標記,但是不再下傳,而是改為詢問時直接計算,當詢問時要往下走就把這個節點的標記計算出來,返回值時再把這些算出的標記的和加上。
注意:
- 在詢問時,\(val\) 的初值是 \(lazy[now]\times(R-L+1)\),而不是 \(lazy[now]\times(r-l+1)\),應該乘詢問的長度而不是當前區間長度。
程式碼
/* Name: SP11470 TTM - To the moon Author: Loceaner Date: 07/09/20 17:31 */ #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define int long long using namespace std; const int A = 1e5 + 11; const int B = 1e6 + 11; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int n, m, root[A], tcnt, a[A]; struct tree { int ls, rs, sum, lazy; } t[A << 5]; void build(int &now, int l, int r) { now = ++tcnt; if (l == r) { t[now].sum = a[l]; return; } int mid = (l + r) >> 1; build(t[now].ls, l, mid), build(t[now].rs, mid + 1, r); t[now].sum = t[t[now].ls].sum + t[t[now].rs].sum; } void update(int &now, int pre, int l, int r, int L, int R, int val) { t[++tcnt] = t[pre]; now = tcnt; if (L <= l && r <= R) { t[now].lazy += val; return; } int mid = (l + r) >> 1; if (L <= mid) update(t[now].ls, t[pre].ls, l, mid, L, R, val); if (R > mid) update(t[now].rs, t[pre].rs, mid + 1, r, L, R, val); t[now].sum = t[t[now].ls].sum + t[t[now].rs].sum + t[t[now].ls].lazy * (mid - l + 1) + t[t[now].rs].lazy * (r - mid); } int query(int now, int l, int r, int L, int R) { if (L == l && r == R) return t[now].sum + t[now].lazy * (r - l + 1); int mid = (l + r) >> 1; int val = (R - L + 1) * t[now].lazy; if (R <= mid) return val + query(t[now].ls, l, mid, L, R); if (L > mid) return val + query(t[now].rs, mid + 1, r, L, R); return val + query(t[now].ls, l, mid, L, mid) + query(t[now].rs, mid + 1, r, mid + 1, R); } signed main() { n = read(), m = read(); for (int i = 1; i <= n; i++) a[i] = read(); build(root[0], 1, n); int x, y, val, tim, now = 0; char opt[2]; while (m--) { scanf("%s", opt); if (opt[0] == 'C') { now++; x = read(), y = read(), val = read(); update(root[now], root[now - 1], 1, n, x, y, val); } else if (opt[0] == 'Q') x = read(), y = read(), cout << query(root[now], 1, n, x, y) << '\n'; else if (opt[0] == 'H') x = read(), y = read(), tim = read(), cout << query(root[tim], 1, n, x, y) << '\n'; else if (opt[0] == 'B') now = read(); else continue; } return 0; }