传送门
【题目分析】
主席树好题,感谢wcr神犇的讲解。
题意很简单,维护树上路径第k小,将两个块联通,所以自然想到LCT或者主席树。
好像有人用主席树+LCT过了这道题但我不会啊
所以老老实实写主席树吧。
用主席树来维护当前点到所在树的根节点的信息,最后统计的答案就是在x->lca->y的路径上进行统计就行了。
考虑到动态加边这种东东,反正我不知道怎么用树剖做,所以就用倍增了。
明显,主席树没法承受1e9的空间,所以进行离散化。
连边的时候,因为要进行权值线段树的合并,所以来一个启发式合并,将复杂度控制为logn。
然后size小的树的节点的fa要记得赋为size大的树的根。
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int MAXM=2e5+10;
int n,m,q,cnt,last;
int a[MAXN],a1[MAXN],N;
int head[MAXN],fat[MAXN],fa[MAXN][20],siz[MAXN],depth[MAXN],vis[MAXN];
int nxt[MAXM],to[MAXM];
int rt[MAXN],tot;
struct Tree{
int l,r;
int siz;
}tr[MAXN*100];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
void add(int x,int y){
nxt[cnt]=head[x];
head[x]=cnt;
to[cnt]=y;
cnt++;
}
int find(int x){
if(x==fat[x])
return x;
return fat[x]=find(fat[x]);
}
void lisan(){
sort(a1+1,a1+n+1);
N=unique(a1+1,a1+n+1)-a1-1;
for(int i=1;i<=n;++i)
a[i]=lower_bound(a1+1,a1+N+1,a[i])-a1;
}
int lca(int x,int y){
if(depth[x]<depth[y])
swap(x,y);
for(int i=16;i>=0;--i){
if(depth[fa[x][i]]>=depth[y])
x=fa[x][i];
}
if(x==y)
return x;
for(int i=16;i>=0;--i){
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
void build(int &root,int l,int r){
root=++tot;
if(l==r)
return ;
int mid=l+r>>1;
build(tr[root].l,l,mid);
build(tr[root].r,mid+1,r);
}
void insert(int &root,int las,int l,int r,int k){
root=++tot;
tr[root]=tr[las];
tr[root].siz++;
if(l==r)
return ;
int mid=l+r>>1;
if(k<=mid)
insert(tr[root].l,tr[las].l,l,mid,k);
else
insert(tr[root].r,tr[las].r,mid+1,r,k);
}
int query(int x,int y,int lc,int flc,int l,int r,int k){
if(l==r)
return a1[l];
int s=tr[tr[x].l].siz+tr[tr[y].l].siz-tr[tr[lc].l].siz-tr[tr[flc].l].siz;
int mid=l+r>>1;
if(k<=s)
return query(tr[x].l,tr[y].l,tr[lc].l,tr[flc].l,l,mid,k);
else
return query(tr[x].r,tr[y].r,tr[lc].r,tr[flc].r,mid+1,r,k-s);
}
void dfs(int u,int f,int root){
fa[u][0]=f;
for(int i=1;i<=16;++i)
fa[u][i]=fa[fa[u][i-1]][i-1];
siz[root]++;
depth[u]=depth[f]+1;
fat[u]=root;
vis[u]=1;
insert(rt[u],rt[f],1,N,a[u]);
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(v==f)
continue;
dfs(v,u,root);
}
}
int main(){
memset(head,-1,sizeof(head));
int test=Read();
n=Read(),m=Read(),q=Read();
for(int i=1;i<=n;++i){
a[i]=a1[i]=Read();
fat[i]=i;
}
lisan();
for(int i=1;i<=m;++i){
int x=Read(),y=Read();
add(x,y),add(y,x);
}
build(rt[0],1,N);
for(int i=1;i<=n;++i){
if(!vis[i]){
dfs(i,0,i);
fat[i]=i;
}
}
while(q--){
char cz[3];
scanf("%s",cz);
if(cz[0]=='Q'){
int x=Read()^last,y=Read()^last,k=Read()^last;
int lc=lca(x,y),flc=fa[lc][0];
last=query(rt[x],rt[y],rt[lc],rt[flc],1,N,k);
cout<<last<<'\n';
}
else{
int x=Read()^last,y=Read()^last;
add(x,y),add(y,x);
int fx=find(x),fy=find(y);
if(siz[fx]<siz[fy])
swap(x,y),swap(fx,fy);
dfs(y,x,fx);
}
}
return 0;
}