ZJOI2006 書架
阿新 • • 發佈:2018-12-10
這道題與普通的\(splay\)不大相同,別的都是以權值來排序,但這道題是以位置進行排序的,也就是對於一個節點,它的左子樹中的節點都在它的上面,右子樹中的節點都在他的下面。
這個比較獨特的一點在於建樹,這次不能再二分查詢要插入的位置了,而是每一次直接把當前插入的點作為上一次插入的點的右兒子(符合上面說的性質),然後\(splay\)一下就好了。
至於置頂和置底操作,實際上就相當於把它的左/右子樹合併到它的後繼/前驅上,這個還是很簡單的。
放書操作的話就是找到前驅和後繼然後直接交換它們的值。
\(ask\)操作就把要找的那個點\(splay\)到根之後輸出其左子樹大小,求排名的話就像\(BST\)
注意因為本題平衡樹是以位置來排序,但是我們在找的時候不能通過\(BST\)的方法找到,所以我們還記錄一下\(pos_i\)表示位置為\(i\)的書在樹上的編號。(這個在執行過插入操作之後就不會變了),這樣就可以了。
一直沒\(debug\)出來竟然是因為多打了一個按位異或……
看一下程式碼。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') #define de putchar('#') #define pr pair<int,int> #define mp make_pair #define fi first #define sc second using namespace std; typedef long long ll; const int M = 100005; const int N = 10000005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >='0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct node { int fa,ch[2],son,cnt,val; }t[M<<1]; int n,m,idx,tot,x,pos[M<<1],root,a; char s[10]; bool get(int x) { return t[t[x].fa].ch[1] == x; } void pushup(int x) { t[x].son = t[t[x].ch[0]].son + t[t[x].ch[1]].son + t[x].cnt; } void rotate(int x) { int y = t[x].fa,z = t[y].fa,k = get(x); t[z].ch[t[z].ch[1] == y] = x,t[x].fa = z; t[y].ch[k] = t[x].ch[k^1],t[t[y].ch[k]].fa = y; t[x].ch[k^1] = y,t[y].fa = x; pushup(x),pushup(y); } void splay(int x,int goal) { while(t[x].fa != goal) { int y = t[x].fa,z = t[y].fa; if(z != goal) (t[y].ch[1] == x) ^ (t[z].ch[1] == y) ? rotate(x) : rotate(y); rotate(x); } if(!goal) root = x; //pos[t[x].val] = x; } void insert(int x) { int u = ++idx; t[u].val = x,pos[x] = u; t[u].son = t[u].cnt = 1; t[u].ch[0] = t[u].ch[1] = 0; if(u > 1) t[u-1].ch[1] = u,t[u].fa = u-1,splay(u,0); } void change(int x,int p) { splay(pos[x],0); if(!t[root].ch[p]) return; if(!t[root].ch[p^1]) t[root].ch[p^1] = t[root].ch[p],t[root].ch[p] = 0; else { int g = t[root].ch[p^1]; while(t[g].ch[p]) g = t[g].ch[p]; t[t[root].ch[p]].fa = g,t[g].ch[p] = t[root].ch[p],t[root].ch[p] = 0; splay(t[g].ch[p],0); } } void modify(int x,int f) { splay(pos[x],0); if(f == 0) return; else if(f == 1) { int g = t[root].ch[1],p = pos[x]; while(t[g].ch[0]) g = t[g].ch[0]; swap(pos[x],pos[t[g].val]); swap(t[p].val,t[g].val); } else if(f == -1) { int g = t[root].ch[0],p = pos[x]; while(t[g].ch[1]) g = t[g].ch[1]; swap(pos[x],pos[t[g].val]); swap(t[p].val,t[g].val); } } void ask(int x) { splay(pos[x],0); printf("%d\n",t[t[root].ch[0]].son); } int rk(int x) { int u = root; while(1) { int y = t[u].ch[0]; if(x <= t[y].son) u = y; else if(x > t[y].son + t[u].cnt) x -= (t[y].son + t[u].cnt),u = t[u].ch[1]; else return t[u].val; } } int main() { //pos[0] = t[0].son = t[0].cnt = t[0].ch[1] = t[0].ch[0] = t[0].fa = t[0].val = 0; n = read(),m = read(); rep(i,1,n) x = read(),insert(x); rep(i,1,m) { scanf("%s",s); if(s[0] == 'T') x = read(),change(x,0); else if(s[0] == 'B') x = read(),change(x,1); else if(s[0] == 'I') x = read(),a = read(),modify(x,a); else if(s[0] == 'A') x = read(),ask(x); else if(s[0] == 'Q') x = read(),printf("%d\n",rk(x)); } return 0; }