P3224 [HNOI2012]永無鄉(fhq-treap題解)
阿新 • • 發佈:2022-04-22
\(《是的我又回來了》\)
題目連結:永無鄉
思路:利用無旋\(treap\)。先看操作\(B\),(因為你不能夠保證一個樹中的所有元素都小於另一顆樹,所以不能通過merge函式將兩樹合併)可以這樣處理,我們考慮兩個\(fhq-treap\)的合併,可以參考啟發式合併的思路,暴力的遍歷一個較小的集合,並將其加入大的集合中。啟發式合併的複雜度是均攤\(\Theta (nlogn)\)。然後再看操作\(Q\),那就是經典\(fhq-treap\)找第\(k\)大的思路。
對於快速判斷屬於哪一個集合,利用並查集。
\(Code\)
const int N = 4e5+10; int fa[N],sz[N]; int found(int x){ if(fa[x] == x)return fa[x]; return fa[x] = found(fa[x]); } struct node { int l,r; int key; int val,tag; int sz; }tr[N]; int tot ,res ,n,m; int a[N]; mt19937 rnd(2884); inline int newnode(int va){ tr[++tot].val = va; tr[tot].sz = 1; tr[tot].key = rnd(); return tot; } int root[N] ; #define lson tr[p].l #define rson tr[p].r inline void pushup(int p){ tr[p].sz = tr[lson].sz + tr[rson].sz + 1; } void split(int p,int k,int &x,int &y){ if(!p)x = y = 0; else { if(tr[p].val <= k){ x = p; split(rson,k,rson,y); }else { y = p; split(lson,k,x,lson); } pushup(p); } } int merge(int x,int y){ if(!x or !y)return x + y ; if(tr[x].key > tr[y].key){ tr[x].r = merge(tr[x].r,y); pushup(x); return x; }else { tr[y].l = merge(x,tr[y].l); pushup(y); return y; } } int idx ; inline void ins(int va){ int x,y,z; split(root[idx],va,x,y); //cout << va <<"!"<< endl; int now = newnode(va); x = merge(x,now); root[idx] = merge(x,y); } void dfs(int id){ if(!id)return ; dfs(tr[id].l); ins(tr[id].val); dfs(tr[id].r); } void Merge(int x,int y){ //if(x == y)return ; idx = x; dfs(root[y]); sz[x] += sz[y]; fa[y] = x; } int h[N]; void split_sz(int p,int k,int &x,int &y){ if(!p)x = y = 0; else { if(tr[lson].sz + 1 <= k){ x = p; split_sz(rson,k-tr[lson].sz-1,rson,y); }else { y = p; split_sz(lson,k,x,lson); } pushup(p); } } void out(int x){ if(!x)return ; out(tr[x].l); cout << tr[x].val << ' '; out(tr[x].r); } void query(int id,int k){ int now = found(id); //cout <<sz[now]<<"@"<<endl; if(sz[now] < k){ puts("-1");return ; } // k = sz[now] - k + 1; int x,y,z; split_sz(root[now],k,x,y); //cout <<k <<"??"<< x <<"!!"<<y<<endl; int idx = x; while(tr[idx].r)idx = tr[idx].r; write(h[tr[idx].val]);pc('\n'); root[now] = merge(x,y); } void solve(){ read(n);read(m); rep(i,1,n){ int t ; read(t);a[i] = t;h[t] = i; } rep(i,1,n){ fa[i] = i;sz[i] = 1; root[i] = newnode(a[i]); } //cout <<tr[root[2]].val<<endl; rep(i,1,m){ int u,v; read(u);read(v); int p = found(u),q = found(v); if(p != q){ if(sz[p] < sz[q])swap(p,q); Merge(p,q); } } int idx = found(1); //out(root[idx]);cout <<endl; int q; read(q); while(q--){ char op[33]; int x,y; scanf("%s%d%d",op,&x,&y); if(*op == 'Q'){ query(x,y); }else { int p = found(x),q = found(y); if(p==q)continue; if(sz[p] < sz[q])swap(p,q); Merge(p,q); } int now = found(1); //cout<<x<<' '<<y<<"::::"; //out(root[now]);cout <<endl; } } signed main(){ solve(); }