题目描述
题目解法
可以发现
x
x
x 到的最远距离的点一定是
x
x
x 所在树的直径的两个端点之一
这个可以用反证法证明
于是考虑维护每个树的直径的两个端点
考虑合并
2
2
2 个树,如果第一个树直径的两个端点分别是
l
1
,
r
1
l1,r1
l1,r1,第二个树直径的两个端点是
l
2
,
r
2
l2,r2
l2,r2,这两棵树是通过
x
−
y
x-y
x−y 连接起来的,那么新树的直径有
6
6
6 种情况,既考虑在原来
2
2
2 棵树内的
2
2
2 种情况,和跨树的
6
6
6 种情况
现在需要快速求出树中
2
2
2 个点的距离,且支持加边操作
可以自然想到用
l
c
t
lct
lct 维护一下
时间复杂度 O ( q l o g n ) O(qlogn) O(qlogn),常数比较大
#include <bits/stdc++.h>
using namespace std;
const int N(300100);
struct Node{
int s[2],fa,tagrev,siz;
}tr[N];
int n,q,stk[N];
int l[N],r[N],fa[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
bool isroot(int x){
return tr[tr[x].fa].s[1]!=x&&tr[tr[x].fa].s[0]!=x;
}
void pushrev(int x){
swap(tr[x].s[0],tr[x].s[1]);
tr[x].tagrev^=1;
}
void pushdown(int x){
if(tr[x].tagrev) pushrev(tr[x].s[0]),pushrev(tr[x].s[1]);
tr[x].tagrev=0;
}
void pushup(int x){
tr[x].siz=tr[tr[x].s[0]].siz+tr[tr[x].s[1]].siz+1;
}
void rotate(int x){
int y=tr[x].fa,z=tr[y].fa;
if(!isroot(y)) tr[z].s[tr[z].s[1]==y]=x;
tr[x].fa=z;
int k=tr[y].s[1]==x;
tr[y].s[k]=tr[x].s[k^1],tr[tr[x].s[k^1]].fa=y;
tr[x].s[k^1]=y,tr[y].fa=x;
pushup(y),pushup(x);
}
void splay(int x){
int top=0,t=x;stk[++top]=t;
while(!isroot(t)) t=tr[t].fa,stk[++top]=t;
while(top) pushdown(stk[top--]);
while(!isroot(x)){
int y=tr[x].fa,z=tr[y].fa;
if(!isroot(y))
if((tr[z].s[1]==y)^(tr[y].s[1]==x)) rotate(x);
else rotate(y);
rotate(x);
}
}
void access(int x){
int z=x;
for(int y=0;x;y=x,x=tr[x].fa){
splay(x);
tr[x].s[1]=y,pushup(x);
}
splay(z);
}
void make_root(int x){
access(x),pushrev(x);
}
int find_root(int x){
access(x);
while(tr[x].s[0]) x=tr[x].s[0];
splay(x);
return x;
}
void link(int x,int y){
make_root(x);
if(find_root(y)!=x) tr[x].fa=y;
}
int get_father(int x){
return x==fa[x]?x:fa[x]=get_father(fa[x]);
}
void split(int x,int y){
make_root(x),access(y);
}
int get_dis(int x,int y){
split(x,y),splay(x);
return tr[x].siz;
}
int main(){
int type=read();
n=read(),q=read();
for(int i=1;i<=n;i++) l[i]=r[i]=i,fa[i]=i;
int lastans=0;
for(int i=1,op,x,y;i<=q;i++){
op=read(),x=read();
if(op==1) y=read();
if(type) x^=lastans,y^=lastans;
if(op==1){
int fax=get_father(x),fay=get_father(y);
link(x,y);
fa[fax]=fay;
int l1=l[fax],r1=r[fax],l2=l[fay],r2=r[fay];
if(get_dis(l1,r1)>get_dis(l[fay],r[fay]))
l[fay]=l1,r[fay]=r1;
if(get_dis(l1,x)+get_dis(y,l2)+1>get_dis(l[fay],r[fay]))
l[fay]=l1,r[fay]=l2;
if(get_dis(l1,x)+get_dis(y,r2)+1>get_dis(l[fay],r[fay]))
l[fay]=l1,r[fay]=r2;
if(get_dis(r1,x)+get_dis(y,l2)+1>get_dis(l[fay],r[fay]))
l[fay]=r1,r[fay]=l2;
if(get_dis(r1,x)+get_dis(y,r2)+1>get_dis(l[fay],r[fay]))
l[fay]=r1,r[fay]=r2;
}
else{
int fax=get_father(x);
printf("%d\n",lastans=max(get_dis(x,l[fax]),get_dis(x,r[fax]))-1);
}
}
return 0;
}