看见题面我就想关掉emmm,文科。。。还是初中历史,说多了都是阴影面积。。。
乍一看,emm?不会啊,看看能不能暴力乱搞,然后我们发现,题中询问最早的操作,那么我们不难发现,在保证留下最早的边并且联通的情况下,最后会连出一棵树,所以我们肯定会想到用并查集啥的维护连通性,但如何知道是哪个操作连接的两个联通块呢?不难发现,按照并查集的操作,我们只会对祖先进行操作,内部的点并不会被影响,所以我们想到了并查集的按秩合并,记录小的联通块连到大的联通块时是第几个操作,由于以后不会有直接的操作连接小联通块和外部节点,所以 这个记录不会被覆盖,查询的时候类似于lca,往上跳的同时更新操作编号的最小值就可以了
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=5e5+50;
int n,m,ti,vis[M];
int fa[M],siz[M],dep[M];
inline int find(int x){return (fa[x]==x?x:find(fa[x]));}
//不能路径压缩,不然深度就一样了
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void constt()
{
for (int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
return ;
}//初始化
inline void unionn(int a,int b)
{
if (siz[a]<=siz[b]) siz[b]+=siz[a],fa[a]=b,vis[a]=ti;
else fa[b]=a,siz[a]+=siz[b],vis[b]=ti;
return ;
}//按秩合并,更新操作的编号
inline void gdep(int x)
{
if (x==fa[x]) return ;gdep(fa[x]);
return (void)(dep[x]=dep[fa[x]]+1);
}//获得深度信息
inline int get(int x,int y)
{
gdep(x);gdep(y);int ans=0;
if (dep[x]<dep[y]) swap(x,y);
while (dep[x]>dep[y]) ans=max(vis[x],ans),x=fa[x];
while (x!=y) ans=max(ans,max(vis[x],vis[y])),x=fa[x],y=fa[y];
return ans;
}//类似于lca更新答案
signed main()
{
n=read();m=read();constt();int ans=0;
while (m--)
{
int fl=read(),a=read(),b=read();
a^=ans,b^=ans;int r1=find(a),r2=find(b);
if (!fl)
{ti++;if (r1!=r2) unionn(r1,r2);}
else
{
if (r1!=r2) ans=0,puts("0");
else ans=get(a,b),printf("%d\n",ans);
}
}
return 0;
}