poj 3580 SuperMemo 題解
阿新 • • 發佈:2020-12-27
一、題目:
二、思路:
很明顯這是一道Splay的噁心題。居然還是一場比賽裡面的,這出題人也夠毒瘤的。
那麼相對於很裸的平衡樹模板題,這道題的操作無非多了一個REVOLVE
。其實也很簡單。我們考慮如果將\(a[l\sim r]\)旋轉\(t\)次,就等效於將\(a[(r-t+1)\sim r]\)放在\(a[l\sim (r-t)]\)的前面。所以我們將區間\(a[l\sim r]\)單拎出來以後(設該區間在平衡樹中的子樹為\(S\)),只需將\(a[r-t+1]\)旋轉到\(S\)的根,然後將\(S.root\)的左子樹(記為\(T\))與\(S.root\)切斷,並將\(T\)
有一個細節需要注意,是在INSERT
操作中。我的方法是將區間\(a[x\sim x]\)單拎出來,在\(a[x]\)下面接上新元素即可。但是需要注意的是,接新元素之前,需要將\(a[x]\)的標記全部清除。這是因為如果沒有及時清除的話,新元素就會在以後的down中被打上標記,而這顯然是不正確的。
三、程式碼:
//先說明一下,為了避免邊界問題,平衡樹中會多兩個元素+inf和-inf,這樣的話每次呼叫kth函式的時候,要將k加上1。 #include <iostream> #include <cstdio> #include <cstring> #include <string> using namespace std; #define LL long long #define mem(s, v) memset(s, v, sizeof s) #define FILEIN(s) freopen(s".in", "r", stdin) #define FILEOUT(s) freopen(s".out", "w", stdout) inline int read(void) { register int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return f * x; } const int maxn = 200005; const int inf = 1e9; int n; int a[maxn]; int root, sz; int son[maxn][2], siz[maxn], fa[maxn]; bool tag[maxn]; int val[maxn], minv[maxn], add[maxn]; inline int get(int x) { return son[fa[x]][1] == x; } inline void update(int x) { siz[x] = siz[son[x][0]] + siz[son[x][1]] + 1; minv[x] = val[x]; if (son[x][0]) minv[x] = min(minv[x], minv[son[x][0]]); if (son[x][1]) minv[x] = min(minv[x], minv[son[x][1]]); } inline void down(int x) { if (tag[x]) { swap(son[x][0], son[x][1]); tag[son[x][0]] ^= 1; tag[son[x][1]] ^= 1; tag[x] = 0; } if (add[x]) { if (son[x][0]) add[son[x][0]] += add[x], val[son[x][0]] += add[x], minv[son[x][0]] += add[x]; if (son[x][1]) add[son[x][1]] += add[x], val[son[x][1]] += add[x], minv[son[x][1]] += add[x]; add[x] = 0; } } inline int build(int l, int r) { if (l > r) return 0; int mid = (l + r) >> 1, now = ++sz; son[now][0] = build(l, mid - 1); fa[son[now][0]] = now; son[now][1] = build(mid + 1, r); fa[son[now][1]] = now; val[now] = a[mid]; update(now); return now; } inline void rotate(int x) { int y = fa[x], z = fa[y], k = get(x); down(y); down(x); son[y][k] = son[x][k ^ 1]; fa[son[y][k]] = y; fa[y] = x; son[x][k ^ 1] = y; fa[x] = z; if (z) son[z][son[z][1] == y] = x; update(y); update(x); } inline void splay(int x, int goal) { for (int f; (f = fa[x]) != goal; rotate(x)) { if (fa[f] != goal) rotate((get(x) == get(f)) ? f : x); } if (!goal) root = x; } inline int kth(int k) { int now = root; while (233) { down(now); if (siz[son[now][0]] >= k) now = son[now][0]; else { k -= siz[son[now][0]]; if (k == 1) return now; --k; now = son[now][1]; } } } inline int pick(int l, int r) {//單拎區間 int tmp1 = kth(l), tmp2 = kth(r + 2); splay(tmp1, 0); splay(tmp2, tmp1); return son[tmp2][0]; } inline void ADD(int l, int r, LL v) { int now = pick(l, r); add[now] += v; minv[now] += v; val[now] += v; splay(now, 0); } inline void REVERSE(int l, int r) { int now = pick(l, r); tag[now] ^= 1; splay(now, 0); } inline void INSERT(int x, LL P) { int now = pick(x, x); down(now);//注意先將標記全部清除 val[++sz] = P; fa[sz] = now; son[now][1] = sz; splay(sz, 0); } inline void DELETE(int x) { int now = pick(x, x); now = fa[now]; son[now][0] = 0; splay(now, 0); } inline void MIN(int l, int r) { int now = pick(l, r); printf("%d\n", minv[now]); } inline void REVOLVE(int l, int r, int t) { t %= (r - l + 1); if (t == 0) return; int now = pick(l, r); now = fa[now]; splay(kth(r - t + 2), now); now = son[now][0]; int x = now; while (233) { down(x); if (!son[x][1]) break; x = son[x][1]; } int y = son[now][0]; fa[y] = x; son[x][1] = y; son[now][0] = 0; splay(y, 0); } int main() { n = read(); for (register int i = 1; i <= n; ++i) { a[i] = read(); } a[0] = -inf; a[n + 1] = inf; root = build(0, n + 1); string opt; int x, y; LL v; int m = read(); while (m--) { cin >> opt; if (opt == "ADD") { x = read(), y = read(), v = read(); ADD(x, y, v); } if (opt == "REVERSE") { x = read(); y = read(); REVERSE(x, y); } if (opt == "REVOLVE") { x = read(), y = read(); v = read(); REVOLVE(x, y, v); } if (opt == "INSERT") { x = read(); v = read(); INSERT(x, v); } if (opt == "DELETE") { x = read(); DELETE(x); } if (opt == "MIN") { x = read(); y = read(); MIN(x, y); } } return 0; }