主席树+倍增
先建好初始状态的主席树和倍增数组,之后每次加边把结点少的树合到结点多的树上,每次合并都要新开结点,所以数组开大点
注意:动态树建倍增数组要把终止条件从log[deep]改为上限19或者更大,因为同一个点的深度会发生变化,如果每次修改不彻底,倍增数组残留的值可能不为0,lca的时候会导致跳过头
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int w[80010],p[80010],d[80010],dis[80010],ed,to[160010],nex[160010],f=0,head[80010],rt[80010],par[80010][20],lg[80010],s[80010],cnt=1;
struct node
{
int l,r,v;
}tree[80010*400];
void build(int l,int r,int &rt,int q,int k)
{
rt=cnt++;
tree[rt]=tree[q];
if(l==r)
{
tree[rt].v++;
return;
}
int mid=(l+r)>>1;
if(k<=mid)
build(l,mid,tree[rt].l,tree[q].l,k);
else
build(mid+1,r,tree[rt].r,tree[q].r,k);
tree[rt].v=tree[tree[rt].l].v+tree[tree[rt].r].v;
}
void dfs(int now,int deep)
{
build(1,ed,rt[now],rt[par[now][0]],w[now]);
d[now]=deep;
s[now]=1;
for(int i=1;i<=lg[deep];++i)
par[now][i]=par[par[now][i-1]][i-1];
for(int i=head[now];i>0;i=nex[i])
{
if(to[i]==par[now][0])
continue;
par[to[i]][0]=now;
p[to[i]]=now;
dfs(to[i],deep+1);
s[now]+=s[to[i]];
}
}
int lca(int x,int y)
{
if(d[x]<d[y])swap(x,y);
while(d[x]>d[y])
x=par[x][lg[d[x]-d[y]]];
if(x==y)
return x;
for(int i=lg[d[x]];i>=0;--i)
{
if(f)
cout<<x<<' '<<d[x]<<' '<<y<<' '<<d[y]<<endl;
if(par[x][i]!=par[y][i])
{
x=par[x][i];y=par[y][i];
}
if(f)
cout<<x<<' '<<d[x]<<' '<<y<<' '<<d[y]<<endl;
}
return par[x][0];
}
int query(int l,int r,int a,int b,int c,int d,int k)
{
if(l==r)
return l;
int sum=tree[tree[a].l].v+tree[tree[b].l].v-tree[tree[c].l].v-tree[tree[d].l].v,mid=(l+r)>>1;
if(k<=sum)
return query(l,mid,tree[a].l,tree[b].l,tree[c].l,tree[d].l,k);
else
return query(mid+1,r,tree[a].r,tree[b].r,tree[c].r,tree[d].r,k-sum);
}
int find(int x)
{return p[x]=p[x]==x?x:find(p[x]);}
int main()
{
// freopen("1.txt","r",stdin);
int t,n,m,ans=0,con=1;
scanf("%d%d%d%d",&t,&n,&m,&t);
for(int i=1;i<=n;++i)
{
scanf("%d",&w[i]);
dis[i]=w[i];
}
sort(dis+1,dis+n+1);
ed=unique(dis+1,dis+n+1)-dis-1;
for(int i=1;i<=n;++i)
w[i]=lower_bound(dis+1,dis+ed+1,w[i])-dis;
for(int i=0;i<m;++i)
{
int a,b;
scanf("%d%d",&a,&b);
to[con]=b;nex[con]=head[a];head[a]=con++;
to[con]=a;nex[con]=head[b];head[b]=con++;
}
lg[0]=-1;
for(int i=1;i<=n;++i)
{
p[i]=i;
lg[i]=lg[i-1];
if(!(i&(i-1)))
++lg[i];
}
for(int i=1;i<=n;++i)
{
if(!s[i])
dfs(i,0);
}
int times=1;
for(int i=1;i<=t;++i)
{
char c;
c=getchar();
while(c!='Q'&&c!='L')
c=getchar();
if(c=='Q')
{
int a,b,k,di;
scanf("%d%d%d",&a,&b,&k);
a^=ans;b^=ans;k^=ans;
if(i==16058)
f=1;
di=lca(a,b);
if(f)
return 0;
ans=dis[query(1,ed,rt[a],rt[b],rt[di],rt[par[di][0]],k)];
}
else
{
int a,b;
scanf("%d%d",&a,&b);
a^=ans;b^=ans;
to[con]=b;nex[con]=head[a];head[a]=con++;
to[con]=a;nex[con]=head[b];head[b]=con++;
int fa=find(a),fb=find(b);
if(s[fa]<=s[fb])
{
p[a]=fb;
s[fb]+=s[fa];
par[a][0]=b;
dfs(a,d[b]+1);
}
else
{
p[b]=fa;
s[fa]+=s[fb];
par[b][0]=a;
dfs(b,d[a]+1);
}
}
}
return 0;
}