BZOJ4668冷战

看见题面我就想关掉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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值