P3224 [HNOI2012]永无乡(fhq-treap题解)
\(《是的我又回来了》\)
题目链接:永无乡
思路:利用无旋\(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();
}