【bzoj2733】永无乡(无旋treap启发式合并 + 并查集)
题目分析
起初每个岛都是一个平衡树, 并查集的祖先都是自己。合并两岛时,pri较小的祖先会被作为合并后的祖先, 而两颗平衡树采用启发式合并。查询k值就是基本操作。
code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> using namespace std; const int N = 1e5 + 5; int n, m; #define SZ(x) (x?x->sze:0) struct node{ node *lc, *rc; int pri, sze, val, num; inline node* upt(){ sze = SZ(lc) + SZ(rc) + 1; return this; } }pool[N], *tail = pool, *nod[N]; int fa[N]; inline int Rand(){ static int RAND_VAL = 1388593021; return RAND_VAL += RAND_VAL << 2 | 1; } inline node* newNode(int v, int k){ node *x = ++tail; x->sze = 1, x->val = v, x->pri = Rand(), x->num = k; return x; } inline node* Merge2(node *u, node *v){ if(!u) return v; if(!v) return u; if(u->pri < v->pri){ u->rc = Merge2(u->rc, v); return u->upt(); } else{ v->lc = Merge2(u, v->lc); return v->upt(); } } inline int getAnc(int a){ return fa[a] == a ? a : (fa[a] = getAnc(fa[a])); } inline void Split_v(node *u, int v, node *&x, node *&y){ if(!u){ x = y = NULL; return; } if(u->val <= v){ Split_v(u->rc, v, x, y); u->rc = NULL, u->upt(); x = Merge2(u, x); } else{ Split_v(u->lc, v, x, y); u->lc = NULL, u->upt(); y = Merge2(y, u); } } inline void Split_k(node *u, int k, node *&x, node *&y){ if(!u){ x = y = NULL; return; } if(SZ(u->lc) < k){ Split_k(u->rc, k - SZ(u->lc) - 1, x, y); u->rc = NULL, u->upt(); x = Merge2(u, x); } else{ Split_k(u->lc, k, x, y); u->lc = NULL, u->upt(); y = Merge2(y, u); } } inline node* Merge(node *u, node *v){ if(!u) return v; if(!v) return u; node *L, *R; if(u->pri > v->pri) swap(u, v); Split_v(v, u->val, L, R); u->lc = Merge(u->lc, L); u->rc = Merge(u->rc, R); return u->upt(); } inline int read(){ int i = 0, f = 1; char ch = getchar(); for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar()); if(ch == '-') f = -1, ch = getchar(); for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0'); return i * f; } inline void wr(int x){ if(x < 0) putchar('-'), x = -x; if(x > 9) wr(x / 10); putchar(x % 10 + '0'); } int main(){ n = read(), m = read(); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= n; i++) nod[i] = newNode(read(), i); for(int i = 1; i <= m; i++){ int a = read(), b = read(); int fu = getAnc(a), fv = getAnc(b); if(fu != fv){ if(nod[fu]->pri < nod[fv]->pri) fa[fv] = fu, nod[fu] = Merge(nod[fu], nod[fv]); else fa[fu] = fv, nod[fv] = Merge(nod[fu], nod[fv]); } } // for(int i = 1; i <= n; i++) cout<<i<<":"<<nod[i]->sze<<endl; int Q = read(); for(int i = 1; i <= Q; i++){ char opt[5]; scanf("%s", opt); if(opt[0] == 'Q'){ node *L, *R, *p, *q; int x = read(), k = read(), fx = getAnc(x); // cout<<x<<" "<<k<<" "<<fx<<" "<<endl; Split_k(nod[fx], k - 1, L, R); Split_k(R, 1, p, q); if(p) wr(p->num); else wr(-1); putchar('\n'); nod[fx] = Merge2(L, Merge2(p, q)); } else{ int a = read(), b = read(); int fu = getAnc(a), fv = getAnc(b); if(fu != fv){ if(nod[fu]->pri < nod[fv]->pri) fa[fv] = fu, nod[fu] = Merge(nod[fu], nod[fv]); else fa[fu] = fv, nod[fv] = Merge(nod[fu], nod[fv]); } } } return 0; }