Q操作:第k小用主席树维护。
L操作:启发式合并暴力做就行了。因为这里保证了连边以后仍然是森林。
注意fa并查集数组和f倍增数组是不一样的,不要用混了。
这里的主席树维护的是当前节点到根节点的信息。
就是说:root[u]对应的这颗树就是从u结点到fa[u]结点(fa[u]是并查集的根,也就是u所在树的根)的这条链的信息。
开始的时候先把空树建出来,也就是把结点都建出来。然后找没被dfs过的点,把所有树给搞出来。
连边的时候,把被合并结点(子树size小一些)的这个树重建。
具体做法:从父亲节点那里继承过来,再增加一个儿子结点的信息就行了。
dfs暴力重建的时候有几个信息要更新:倍增数组、被合并子树结点的fa值(都指向size大一些的那个子树的集合根,这两个集合被合成了一个集合)、合并出来的集合的大小、结点深度。初始建森林的时候要记一个vis数组以区分不同的树。
蓝树大一些,红树小一些。那么把红树合到A上。从A开始dfs。大概就是这个意思。
然而这题有点坑啊,很容易RE。。而且testcase是打酱油的。。。。。
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
const int maxn=80010;
char op[5];
int n,m,t,testcase,M,x,y,g,k,lastans=0;
int Head[maxn],Next[maxn<<1],V[maxn<<1],val[maxn],cpy[maxn],fa[maxn],cnt=0;
int f[maxn][17],siz[maxn],dep[maxn],vis[maxn],root[maxn],tot=0;
struct node{int siz,ls,rs;}tr[maxn*600];
int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
int getfa(int x){return (fa[x]==x)?(x):(fa[x]=getfa(fa[fa[fa[x]]]));}
void disc(){
sort(cpy+1,cpy+n+1),M=unique(cpy+1,cpy+n+1)-cpy-1;
for(int i=1;i<=n;++i) val[i]=lower_bound(cpy+1,cpy+M+1,val[i])-cpy;
}
int getlca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=16;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
if(u==v) return u;
for(int i=16;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][0];
}
void build(int &root,int l,int r){
tr[root=++tot].siz=0;
if(l==r) return;
build(tr[root].ls,l,mid);
build(tr[root].rs,mid+1,r);
}
void Insert(int &rt,int pre,int l,int r,int val){
tr[rt=++tot]=tr[pre],tr[rt].siz++;
if(l==r) return;
if(val<=mid) Insert(tr[rt].ls,tr[pre].ls,l,mid,val);
else Insert(tr[rt].rs,tr[pre].rs,mid+1,r,val);
}
int query(int x,int y,int g,int fg,int l,int r,int k){
if(l==r) return cpy[l];
int now=tr[tr[x].ls].siz+tr[tr[y].ls].siz-tr[tr[g].ls].siz-tr[tr[fg].ls].siz;
if(k<=now) return query(tr[x].ls,tr[y].ls,tr[g].ls,tr[fg].ls,l,mid,k);
else return query(tr[x].rs,tr[y].rs,tr[g].rs,tr[fg].rs,mid+1,r,k-now);
}
void dfs(int u,int F,int rt){
f[u][0]=F;for(int i=1;i<=16;++i) f[u][i]=f[f[u][i-1]][i-1];
siz[rt]++,dep[u]=dep[F]+1,fa[u]=rt,vis[u]=1;
Insert(root[u],root[F],1,M,val[u]);
for(int i=Head[u];i;i=Next[i]) if(V[i]!=F)
dfs(V[i],u,rt);
}
inline void print(int x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
int main(){
testcase=read(),n=read(),m=read(),t=read();
for(int i=1;i<=n;++i) val[i]=read(),fa[i]=i,cpy[i]=val[i];
while(m--) x=read(),y=read(),add(x,y),add(y,x);
disc(),build(root[0],1,M);
for(int i=1;i<=n;++i) if(!vis[i]) dfs(i,0,i);
while(t--){
scanf("%s",op);
if(op[0]=='Q'){
x=read()^lastans,y=read()^lastans,k=read()^lastans,g=getlca(x,y);
lastans=query(root[x],root[y],root[g],root[f[g][0]],1,M,k);
print(lastans),putchar('\n');
}
if(op[0]=='L'){
x=read()^lastans,y=read()^lastans;
add(x,y),add(y,x);
int fx=getfa(x),fy=getfa(y);
if(siz[fx]<siz[fy]) swap(x,y),swap(fx,fy);
dfs(y,x,fx);
}
}
}