好久没写blog了,可能是因为最近比较忙吧,距离noip2017也就60个小时左右了吧。
要开始复习一下模板了。
这道题问是否联通,显然要用并查集来做,但是,是否能路径合并呢?
简单想一想,当然不能啦,因为我们每个结点上要记录一个时间标记,然后构成一个像树一样的结构(当然可能有其它做法)。
但是,裸的并查集会超时的,如何优化呢?
并查集主要优化就两个:路径压缩和按秩合并,前者接近O(n),后者能让高度变小,但我也不知道具体是多少,大概logn?
所以,我们就按秩合并一下就可以过了。
什么是按秩合并?我也不太清楚真正的,网上的说法也太多,我的意思就是记录一下每个集合的元素个数,合并时,小的接在大的上。
询问的话,朴素的来,就是树上路径求一个最大值。
先处理深度,再类似lca一个一个跳。
#include<bits/stdc++.h>
#define N 500000
#define Max(a,b,c) max(max(a,b),c)
using namespace std;
int n,m,x,y,opt,last,fx,fy,T;
int f[N+5],v[N+5],siz[N+5],dep[N+5];
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,b=1;
char c=nc();
for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
return x*b;
}
inline int find(int x)
{
return x==f[x]?f[x]:find(f[x]);
}
inline void pre(int x)
{
if(x==f[x])return;
pre(f[x]);
dep[x]=dep[f[x]]+1;
}
inline int ask(int x,int y)
{
pre(x),pre(y);
if(dep[x]<dep[y])swap(x,y);
int mx=0;
while(dep[x]>dep[y]&&x!=y)mx=max(mx,v[x]),x=f[x];
while(x!=y)mx=Max(mx,v[x],v[y]),x=f[x],y=f[y];
return mx;
}
int main()
{
freopen("in.txt","r",stdin);
n=read(),m=read();
for(int i=1;i<=n;i++)f[i]=i,siz[i]=1;
for(int i=1;i<=m;i++)
{
opt=read(),x=read(),y=read();
x^=last,y^=last;
if(opt==0)
{
fx=find(x),fy=find(y);
T++;
if(fx==fy)continue;
if(siz[fx]>siz[fy])swap(fx,fy);
f[fx]=fy;
siz[fy]+=siz[fx];
v[fx]=T;
}
else
{
fx=find(x),fy=find(y);
if(fx!=fy)printf("%d\n",last=0);
else printf("%d\n",last=ask(x,y));
}
}
return 0;
}