POJ 3580 SuperMemo (Splay)
思路:
區間的一系列操作, 還有翻轉什麼的,顯然Splay
主要說一下 那個迴圈右移的操作吧
次數先對總長度取模, 因為相當於有迴圈節。
然後 這個操作 相當於 把一個區間分成兩個子區間, 把後面挪到前面。
假設兩個區間是 [s1, e1]和 [s2, e2]
那麼先把s2-1 轉到根, e2+1 轉到根的下面, 將e2轉到e2+1的下面,將 e2+1的左子樹 切下來。
這樣就把後一個區間拿出來了, 同樣的操作 將s1-1轉到根, s1 轉到根的下面, 插到 s1左子樹即可。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 200000 + 10; int n, m; int num[maxn]; const int inf = 0x3f3f3f3f; struct SplayTree{ void Rotate(int x, int f){ int y = pre[x], z = pre[y]; pushdown(x); pushdown(y); ch[y][!f] = ch[x][f]; pre[ch[x][f] ] = y; ch[x][f] = y; pre[y] = x; pre[x] = z; if (pre[x]) ch[z][ch[z][1] == y ] = x; pushup(y); } void Splay(int x,int goal){ pushdown(x); while(pre[x] != goal){ if (pre[pre[x] ] == goal){ Rotate(x, ch[pre[x] ][0] == x); } else { int y = pre[x], z = pre[y]; int f = (ch[z][0] == y); if (ch[y][f] == x) Rotate(x, !f), Rotate(x, f); else Rotate(y, f), Rotate(x, f); } } pushup(x); if (goal == 0) root = x; } void RotateTo(int k,int goal){ int x = root; pushdown(x); while(sz[ ch[x][0] ] != k){ if (k < sz[ ch[x][0] ]){ x = ch[x][0]; } else { k -= (sz[ ch[x][0] ] + 1); x = ch[x][1]; } pushdown(x); } Splay(x, goal); } void clear(){ ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0; top = 0; root = n = 0; val[0] = -inf; Min[0] = inf; rev[0] = 0; add[0] = 0; NewNode(root, -inf); NewNode(ch[root][1], inf); pre[n] = root; sz[root] = 2; } void NewNode(int& x,int c){ if (top) x = pool[--top]; else x = ++n; ch[x][0] = ch[x][1] = pre[x] = 0; sz[x] = 1; val[x] = Min[x] = c; } void pushup(int x){ sz[x] = 1 + sz[ch[x][0] ] + sz[ch[x][1] ]; Min[x] = min(val[x] , min(Min[ch[x][0] ] , Min[ch[x][1] ])); } void pushdown(int x){ if (rev[x]){ update_rev(ch[x][0]); update_rev(ch[x][1]); rev[x] = 0; } if (add[x]){ update_add(ch[x][0], add[x]); update_add(ch[x][1], add[x]); add[x] = 0; } } void init(int pos, int tot){ clear(); cnt = tot; RotateTo(pos, 0); RotateTo(pos + 1, root); build(ch[ ch[root][1] ][0], 1, tot, ch[root][1]); pushup(ch[root][1]); pushup(root); } void build(int& x,int l,int r,int f){ if (l > r) return ; int mid = (l + r) >> 1; NewNode(x, num[mid]); build(ch[x][0],l, mid-1, x); build(ch[x][1], mid+1, r, x); pre[x] = f; pushup(x); } void update_add(int x,int v){ if (!x) return; val[x] += v; Min[x] += v; add[x] += v; } void update_rev(int x){ if (!x) return; swap(ch[x][0], ch[x][1]); rev[x] ^= 1; } void ADD(int l,int r,int c){ RotateTo(l - 1, 0); RotateTo(r + 1, root); int key = ch[ch[root][1] ][0]; update_add(key, c); pushup(ch[root][1]); pushup(root); } int getmin(int l,int r){ RotateTo(l-1,0); RotateTo(r+1,root); int key = ch[ch[root][1] ][0]; return Min[key]; } void reverse(int l, int r){ RotateTo(l-1, 0); RotateTo(r + 1, root); int key = ch[ ch[root][1] ][0]; update_rev(key); } void erase(int x){ if (!x) return; pool[top++] = x; erase(ch[x][0]); erase(ch[x][1]); } void del(int x){ RotateTo(x-1, 0); RotateTo(x+1, root); int key = ch[ ch[root][1] ][0]; ch[ ch[root][1] ][0] = 0; cnt -= sz[key]; erase(key); pushup(ch[root][1]); pushup(root); } void insert(int pos, int v){ cnt++; RotateTo(pos, 0); RotateTo(pos + 1, root); num[1] = v; build(ch[ ch[root][1] ][0], 1, 1, ch[root][1]); pushup(ch[root][1]); pushup(root); } void revolve(int x, int y, int t){ t %= (y-x+1); if (t < 0) t = y - x + 1 + t; if (t == 0) return; int s2 = y - t + 1, e2 = y; int s1 = x, e1 = s2 - 1; RotateTo(s2 - 1, 0); RotateTo(e2 + 1, root); int haha = ch[root][1]; RotateTo(e2, haha); int key = ch[ ch[root][1] ][0]; pre[key] = 0; ch[ch[root][1] ][0] = 0; pushup(ch[root][1]); pushup(root); RotateTo(s1 - 1, 0); RotateTo(s1, root); ch[ch[root][1] ][0] = key; pre[key] = ch[root][1]; pushup(ch[root][1]); pushup(root); } int root, n, cnt, ct, top; int ch[maxn][2]; int pre[maxn]; int sz[maxn]; int val[maxn]; int Min[maxn]; int add[maxn]; int pool[maxn]; int rev[maxn]; }spt; int main(){ int n; scanf("%d",&n); for (int i = 1; i <= n; ++i){ scanf("%d", &num[i]); } int q; spt.init(0, n); scanf("%d", &q); char op[10]; while(q--){ scanf("%s", op); if (op[0] == 'A'){ int x, y, d; scanf("%d %d %d",&x, &y, &d); spt.ADD(x, y, d); } else if (op[0] == 'R'){ if (op[3] == 'E'){ int x, y; scanf("%d %d",&x, &y); spt.reverse(x, y); } else { int x, y, t; scanf("%d %d %d", &x, &y, &t); spt.revolve(x, y, t); } } else if (op[0] == 'I'){ int x, p; scanf("%d %d",&x, &p); spt.insert(x, p); } else if (op[0] == 'D'){ int x; scanf("%d", &x); spt.del(x); } else { int x, y; scanf("%d %d", &x, &y); printf("%d\n", spt.getmin(x, y)); } } return 0; }
SuperMemo
Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A
To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls. Input The first line contains n (n ≤ 100000). The following n lines describe the sequence. Then follows M (M ≤ 100000), the numbers of operations and queries. The following M lines describe the operations and queries. Output For each "MIN" query, output the correct answer. Sample Input 5 1 2 3 4 5 2 ADD 2 4 1 MIN 4 5 Sample Output 5 Source |