☆ [ZJOI2006] 書架 「平衡樹維護數列」
阿新 • • 發佈:2018-09-16
insert targe play amp bottom https efi 查詢 tdi ,相當於是\(idx\)數組的逆運算。在知道一個外部編號時,能夠迅速找到其所對應的節點編號。然後就可以對其進行直接操作了
題目類型:平衡樹
傳送門:>Here<
題意:要求維護一個數列,支持:將某個元素置頂或置底,交換某元素與其前驅或後繼的位置,查詢編號為\(S\)的元素的排名,查詢排名第\(k\)的元素編號
解題思路
可以說是平衡樹維護數列的入門題。當平衡樹在維護數列時,關鍵字是在數列中的排名。因此中序遍歷即為當前數列。註意在平衡樹維護數列中,會涉及到兩個編號。一個編號是這個節點在平衡樹內的編號,一般外界是不會直接訪問的。另一個是題目賦予的編號,代表這個位置數列上對應的值。外部編號即為一個附加值。當我們需要找到外部編號為\(S\)的元素,好像比較麻煩。此時,我們需要多開一個數組\(pos\),令\(pos[idx[o]]=o\)
至於前驅後繼交換,我們只需要交換這兩個節點所對應的外部編號以及更新\(pos\),沒有必要交換平衡樹內的節點。
Code
/*By DennyQi 2018*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() using namespace std; typedef long long ll; const int MAXN = 80010; const int INF = 1061109567; inline int Max(const int a, const int b){ return (a > b) ? a : b; } inline int Min(const int a, const int b){ return (a < b) ? a : b; } inline int read(){ int x = 0; int w = 1; register char c = getchar(); for(; c ^ '-' && (c < '0' || c > '9'); c = getchar()); if(c == '-') w = -1, c = getchar(); for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w; } int N,M,S,T; char opt[10]; int idx[MAXN],pos[MAXN]; struct Splay{ int fa[MAXN],ch[MAXN][2],size[MAXN],num_node,rt; inline void update(int x){ size[x] = 1; if(ch[x][0]) size[x] += size[ch[x][0]]; if(ch[x][1]) size[x] += size[ch[x][1]]; } inline bool rson(int f, int x){ return ch[f][1] == x; } inline void rotate(int x){ int f = fa[x], gf = fa[f]; bool p = rson(f, x), q = !p; if(!gf) rt = x; else ch[gf][rson(gf,f)] = x; fa[x] = gf; ch[f][p] = ch[x][q], fa[ch[x][q]] = f; ch[x][q] = f, fa[f] = x; update(f), update(x); } inline void splay(int x, int target){ int f,gf; while(fa[x] != target){ f = fa[x], gf = fa[f]; if(gf == target){ rotate(x); break; } if(rson(gf,f) ^ rson(f,x)) rotate(x); else rotate(f); rotate(x); } } inline void init(int id){ if(!rt){ rt = ++num_node; idx[num_node] = id; pos[id] = num_node; size[num_node] = 1; return; } int pre_rt = rt; rt = ++num_node; ch[rt][0] = pre_rt; fa[pre_rt] = rt; size[rt] = size[pre_rt] + 1; idx[rt] = id; pos[id] = rt; } inline void top(int s){ int o = pos[s]; splay(o, 0); if(!ch[rt][0] && !ch[rt][1]) return; int p = ch[rt][1]; if(!p){ ch[rt][1] = ch[rt][0]; ch[rt][0] = 0; splay(ch[rt][1], 0); return; } while(ch[p][0]) p = ch[p][0]; splay(p, rt); ch[p][0] = ch[rt][0]; fa[ch[rt][0]] = p; ch[rt][0] = 0; update(p), update(rt); } inline void bottom(int s){ int o = pos[s]; splay(o, 0); if(!ch[rt][0] && !ch[rt][1]) return; int p = ch[rt][0]; if(!p){ ch[rt][0] = ch[rt][1]; ch[rt][1] = 0; splay(ch[rt][0], 0); return; } while(ch[p][1]) p = ch[p][1]; splay(p, rt); ch[p][1] = ch[rt][1]; fa[ch[rt][1]] = p; ch[rt][1] = 0; update(p), update(rt); } inline int ask(int s){ int o = pos[s]; splay(o, 0); return size[ch[rt][0]]; } inline int query(int k){ int o = rt; while(o){ if(size[ch[o][0]] >= k){ o = ch[o][0]; } else if(size[ch[o][0]] + 1 < k){ k -= size[ch[o][0]] + 1; o = ch[o][1]; } else{ return idx[o]; } } return -1; } inline void insert(int S, int T){ if(T == 0) return; splay(pos[S], 0); if(T == -1){ int o = ch[rt][0]; while(ch[o][1]) o = ch[o][1]; splay(o, rt); swap(idx[rt], idx[o]); pos[idx[rt]] = rt, pos[idx[o]] = o; update(o), update(rt); } if(T == 1){ int o = ch[rt][1]; while(ch[o][0]) o = ch[o][0]; splay(o, rt); swap(idx[rt], idx[o]); pos[idx[rt]] = rt, pos[idx[o]] = o; update(o), update(rt); } } }qxz; int main(){ scanf("%d %d", &N, &M); for(int i = 1; i <= N; ++i){ scanf("%d", &S); qxz.init(S); } while(M--){ scanf("%s %d", opt, &S); if(opt[0] == 'T'){ qxz.top(S); } if(opt[0] == 'B'){ qxz.bottom(S); } if(opt[0] == 'A'){ printf("%d\n", qxz.ask(S)); } if(opt[0] == 'Q'){ printf("%d\n", qxz.query(S)); } if(opt[0] == 'I'){ scanf("%d", &T); qxz.insert(S,T); } } }
☆ [ZJOI2006] 書架 「平衡樹維護數列」