题面:https://loj.ac/problem/6038
题解
居然在原题重测(原题重错、新题爆错)的考场上切了一道LCT的题
一看就是维护森林中每棵树的直径
以为可以用倍增LCA来求两点距离,然而它强制在线
想了一下,发现可以用LCT来求两点距离
因为所有的边权都为1,所以我们把一条链spilt出来后得到的链的节点数-1就是两点的距离
然后合并两棵树的时候用并查集来记录一下直径的长度以及两个端点,用LCT算4个点对的距离然后更新即可
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
char c;int num=0,flg=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num*flg;
}
#define N 300005
namespace LCT{
int fa[N],ch[N][2],siz[N];
bool rev[N];
bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
bool pdc(int x){return ch[fa[x]][1]==x;}
void pushdown(int x){
if(rev[x]){
swap(ch[x][0],ch[x][1]);
if(ch[x][0])rev[ch[x][0]]^=1;
if(ch[x][1])rev[ch[x][1]]^=1;
rev[x]=0;
}
}
void pushup(int x){siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
void rot(int x){
int y=fa[x],z=fa[y];
bool flg=pdc(x);
if(nrt(y))ch[z][pdc(y)]=x;
if(ch[y][flg]=ch[x][flg^1])
fa[ch[y][flg]]=y;
ch[x][flg^1]=y;
fa[y]=x;fa[x]=z;
pushup(y);pushup(x);
}
void pdpath(int x){if(nrt(x))pdpath(fa[x]);pushdown(x);}
void splay(int x){
pdpath(x);
for(;nrt(x);rot(x))
if(nrt(fa[x]))rot(pdc(x)==pdc(fa[x])?fa[x]:x);
}
void Access(int x){
for(int i=0;x;i=x,x=fa[x]){
splay(x);
ch[x][1]=i;
pushup(x);
}
}
void beroot(int x){
Access(x);
splay(x);
rev[x]^=1;
}
void link(int x,int y){
beroot(x);
fa[x]=y;
}
int dis(int x,int y){
beroot(x);Access(y);splay(y);
return siz[y];
}
}//----LCT----
int fa[N],A[N],B[N],H[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int hh,tmp1,tmp2;
void update(int cd,int t1,int t2)
{
if(hh<cd){hh=cd;tmp1=t1;tmp2=t2;}
}
void HB(int x,int y)// !!!!
{
x=find(x);y=find(y);
if(x!=y){
fa[y]=x;
hh=H[x];tmp1=A[x];tmp2=B[x];
update(H[y],A[y],B[y]);
update(LCT::dis(A[x],A[y]),A[x],A[y]);
update(LCT::dis(A[x],B[y]),A[x],B[y]);
update(LCT::dis(B[x],A[y]),B[x],A[y]);
update(LCT::dis(B[x],B[y]),B[x],B[y]);
H[x]=hh;A[x]=tmp1;B[x]=tmp2;
}
}
int getans(int x)
{
int f=find(x);
return max(LCT::dis(x,A[f]),LCT::dis(x,B[f]));
}
int main()
{
int tp,op,n,Q,i,u,v,ans=0;
tp=gi();n=gi();Q=gi();
for(i=1;i<=n;i++)fa[i]=A[i]=B[i]=i,H[i]=1;
while(Q--){
op=gi();
if(op==1){
u=gi();v=gi();
if(tp)u^=ans,v^=ans;
LCT::link(u,v);
HB(u,v);
}
else{
u=gi();
if(tp)u^=ans;
ans=getans(u)-1;// !!!!
printf("%d\n",ans);
}
}
}
hehe
考试的时候不知道为什么RE了,后来发现自己没有记录lastans
再交一发还是RE,换了一种合并的方式就A了
(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・(・∀・*)
Σ(っ °Д °;)っ≧ ﹏ ≦Σ(っ °Д °;)っ≧ ﹏ ≦Σ(っ °Д °;)っ≧ ﹏ ≦Σ(っ °Д °;)っ≧ ﹏ ≦Σ(っ °Д °;)っ≧ ﹏ ≦Σ(っ °Д °;)っ