题目描述:
给出一个森林
求 1 : u -> v 路径上的第K小值
2:u v 合并 u v 所在树
题目分析:
合并?LCT?
LCT没法维护第K值啊(雾
动态维护第K值肯定是要用主席树的
在树上建立主席树,我们新的节点继承父亲树信息
查询的时候求LCA,然后消除影响
合并的话我们就搞一下启发式合并qwq
O(Q∗logn2)
O
(
Q
∗
l
o
g
n
2
)
题目链接:
Ac 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxm=8e4+10;
int ls[maxm*500],rs[maxm*500],sum[maxm*500],siz[maxm];
int rt[maxm],sz,t;
int fa[maxm],f[maxm][18];
int hash[maxm],val[maxm],deep[maxm];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
bool vis[maxm];
int n,m,q;
int head[maxm],to[maxm<<1],net[maxm<<1],cnt;
void addedge(int u,int v)
{cnt++;to[cnt]=v,net[cnt]=head[u],head[u]=cnt;}
void insert(int &now,int pre,int l,int r,int ind)
{
now=++sz;
ls[now]=ls[pre],rs[now]=rs[pre],sum[now]=sum[pre]+1;
if(l>=r) return;
int mid=(l+r)>>1;
if(ind<=mid) insert(ls[now],ls[pre],l,mid,ind);
else insert(rs[now],rs[pre],mid+1,r,ind);
}
int find_kth(int s,int t,int lca,int lcaf,int l,int r,int rank)
{
int nowsum=sum[ls[s]]+sum[ls[t]]-sum[ls[lca]]-sum[ls[lcaf]];
if(l>=r) return l;
int mid=(l+r)>>1;
if(nowsum>=rank) return find_kth(ls[s],ls[t],ls[lca],ls[lcaf],l,mid,rank);
else return find_kth(rs[s],rs[t],rs[lca],rs[lcaf],mid+1,r,rank-nowsum);
}
int dfs(int now,int fax,int root)
{
f[now][0]=fax;
for(int i=1;i<=16;i++)
f[now][i]=f[f[now][i-1]][i-1];
siz[root]++,deep[now]=deep[fax]+1,fa[now]=root;vis[now]=1;
insert(rt[now],rt[fax],1,t,val[now]);
for(int i=head[now];i;i=net[i])
if(to[i]!=fax) dfs(to[i],now,root);
}
int LCA(int u,int v)
{
if(deep[u]<deep[v]) std::swap(u,v);
//printf("%d %d\n",u,v);
for(int i=16;~i;i--)
{
//printf("%d %d %d %d\n",deep[u],deep[v],f[u][i],deep[f[u][i]]);
if(deep[f[u][i]]>=deep[v]) u=f[u][i];
}
if(u==v) return u;
for(int i=16;~i;i--)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}
int main()
{
int T;
scanf("%d",&T);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]),hash[i]=val[i],fa[i]=i;
std::sort(hash+1,hash+n+1);
t=std::unique(hash+1,hash+n+1)-hash-1;
for(int i=1;i<=n;i++)
val[i]=std::lower_bound(hash+1,hash+t+1,val[i])-hash;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
int tot=0;
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i,0,++tot),fa[tot]=tot;
//for(int i=0;i<=n;i++) printf("%d\n",deep[i]);
int last=0;
for(int i=1,x,y;i<=q;i++)
{
char s[10];
scanf("%s%",s);
if(s[0]=='Q')
{
int k;
scanf("%d%d%d",&x,&y,&k);
x^=last,y^=last;
k^=last;
int lca=LCA(x,y);
last=hash[find_kth(rt[x],rt[y],rt[lca],rt[f[lca][0]],1,t,k)];
printf("%d\n",last);
}
else
{
scanf("%d%d",&x,&y);
x^=last,y^=last;
addedge(x,y),addedge(y,x);
int f1=find(x),f2=find(y);
if(siz[f1]<siz[f2]) std::swap(f1,f2),std::swap(x,y);
dfs(y,x,f1);
}
}
return 0;
}