題目描述數據結構
輸入學習
輸出spa
樣例輸入blog
5
1 2
1 1
1 3
4
5it
樣例輸出io
1
2
2
2
2class
題解效率
Splay 線段樹+STL-setdate
這道題的關鍵之處在於:除了插入之外,只操做最大/最小值。二叉樹
因此每次旋轉只有一個固定方向。
以旋轉最小值爲例,必定是不斷的進行zig操做最終旋轉到根。
經過找規律能夠證實這種操做以後,最小節點深度變爲1,原來最小節點的右子樹深度不變,其他節點深度+1而且結構不變。
而右子樹必定是一段連續的區間,這樣咱們可使用線段樹維護這個過程,同時還要維護每一個節點的父親和兒子,這個不難維護。
刪除的時候,把根節點刪掉,其他節點深度-1且結構不變。
這樣2345操做都搞定了,只剩下1操做。
考慮到插入一個數x,必定是在它的前驅pro或後繼sub其一插入,並且必定存在某個節點不存在相應的兒子。
具體地,有個結論:pro和sub的深度必定不一樣,且深度大的能夠插入。
具體證實很簡單,在這裏不細講了。
這樣只要知道前驅後繼便可,能夠在線段樹上求,但我懶了直接上set搞定。
#include <cstdio> #include <algorithm> #include <set> #define N 100010 #define lson l , mid , x << 1 #define rson mid + 1 , r , x << 1 | 1 using namespace std; set<int> s; set<int>::iterator it , pro , sub; int sum[N << 2] , si[N << 2] , tag[N << 2] , ls[N] , rs[N] , fa[N] , opt[N] , a[N] , v[N] , tot , root; void pushup(int x) { sum[x] = sum[x << 1] + sum[x << 1 | 1] , si[x] = si[x << 1] + si[x << 1 | 1]; } void pushdown(int x) { if(tag[x]) { sum[x << 1] += si[x << 1] * tag[x] , tag[x << 1] += tag[x]; sum[x << 1 | 1] += si[x << 1 | 1] * tag[x] , tag[x << 1 | 1] += tag[x]; tag[x] = 0; } } void change(int p , int o , int d , int l , int r , int x) { if(l == r) { si[x] += o , sum[x] += d; return; } pushdown(x); int mid = (l + r) >> 1; if(p <= mid) change(p , o , d , lson); else change(p , o , d , rson); pushup(x); } void update(int b , int e , int a , int l , int r , int x) { if(b <= l && r <= e) { sum[x] += a * si[x] , tag[x] += a; return; } pushdown(x); int mid = (l + r) >> 1; if(b <= mid) update(b , e , a , lson); if(e > mid) update(b , e , a , rson); pushup(x); } int query(int p , int l , int r , int x) { if(l == r) return sum[x]; pushdown(x); int mid = (l + r) >> 1; if(p <= mid) return query(p , lson); else return query(p , rson); } int main() { int m , i , d; scanf("%d" , &m); for(i = 1 ; i <= m ; i ++ ) { scanf("%d" , &opt[i]); if(opt[i] == 1) scanf("%d" , &a[i]) , v[++tot] = a[i]; } sort(v + 1 , v + tot + 1); for(i = 1 ; i <= m ; i ++ ) if(opt[i] == 1) a[i] = lower_bound(v + 1 , v + tot + 1 , a[i]) - v; for(i = 1 ; i <= m ; i ++ ) { if(opt[i] == 1) { if(s.empty()) root = a[i] , d = 1; else { it = s.upper_bound(a[i]) , sub = it; if(sub == s.begin()) ls[*sub] = a[i] , fa[a[i]] = *sub , d = query(*sub , 1 , tot , 1) + 1; else { pro = --it; if(sub == s.end()) rs[*pro] = a[i] , fa[a[i]] = *pro , d = query(*pro , 1 , tot , 1) + 1; else if(query(*sub , 1 , tot , 1) < query(*pro , 1 , tot , 1)) rs[*pro] = a[i] , fa[a[i]] = *pro , d = query(*pro , 1 , tot , 1) + 1; else ls[*sub] = a[i] , fa[a[i]] = *sub , d = query(*sub , 1 , tot , 1) + 1; } } printf("%d\n" , d); change(a[i] , 1 , d , 1 , tot , 1); s.insert(a[i]); } else if(opt[i] % 2 == 0) { it = s.begin() , d = query(*it , 1 , tot , 1); printf("%d\n" , d); if(*it != root) { update(1 , tot , 1 , 1 , tot , 1); update(*it , *it , -d , 1 , tot , 1); int t = fa[*it]; ls[t] = fa[*it] = 0; if(rs[*it]) update(*it + 1 , t - 1 , -1 , 1 , tot , 1) , fa[rs[*it]] = t , ls[t] = rs[*it]; rs[*it] = root , fa[root] = *it , root = *it; } if(opt[i] == 4) root = rs[*it] , rs[*it] = fa[root] = 0 , change(*it , -1 , -1 , 1 , tot , 1) , update(1 , tot , -1 , 1 , tot , 1) , s.erase(*it); } else { it = s.end() , it -- , d = query(*it , 1 , tot , 1); printf("%d\n" , d); if(*it != root) { update(1 , tot , 1 , 1 , tot , 1); update(*it , *it , -d , 1 , tot , 1); int t = fa[*it]; rs[t] = fa[*it] = 0; if(ls[*it]) update(t + 1 , *it - 1 , -1 , 1 , tot , 1) , fa[ls[*it]] = t , rs[t] = ls[*it]; ls[*it] = root , fa[root] = *it , root = *it; } if(opt[i] == 5) root = ls[*it] , ls[*it] = fa[root] = 0 , change(*it , -1 , -1 , 1 , tot , 1) , update(1 , tot , -1 , 1 , tot , 1) , s.erase(*it); } } return 0; }