BZOJ 4668 冷战
2017.09.11
2017.09.11
给你一个双向无边图,每次加入一条边或者询问:将两个点联通的最早的边是哪条?
因为是双向的所以没必要真的加边——如果两个点已经联通再连边是没有意义的。维护节点关系那么当然是用并查集啊qwq
插入的时候遵循按秩合并——深度小的合并到深度大的,更新被合并点的答案。
查询的时候首先判断这俩点father一不一样。如果一样的话重新开始,两个点类似LCA向上爬升。每个点的权值是它最后合并的时间戳,所以找到沿途最大的时间戳就是最终的答案了。
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,mode,u,v,ans,fa[500010],d[500010],tot;
int main()
{
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%d%d%d",&mode,&u,&v);
u^=ans,v^=ans;
switch(mode)
{
case 0:
{
int tu=0,tv=0;++tot;
while(fa[u]) u=fa[u],tu++;
while(fa[v]) v=fa[v],tv++;
if(u!=v)
{
if(tu>tv) swap(u,v);
fa[u]=v,d[u]=tot;
}
break;
}
case 1:
{
int tu=u,tv=v,du=0,dv=0;ans=0;
while(fa[u]) u=fa[u],du++;
while(fa[v]) v=fa[v],dv++;
if(u==v)
{
if(du<dv) swap(du,dv),swap(tu,tv);
u=tu,v=tv;
for(int j=1;j<=du-dv;j++) ans=max(ans,d[u]),u=fa[u];
while(u!=v) ans=max(ans,max(d[u],d[v])),u=fa[u],v=fa[v];
}
printf("%d\n",ans);
break;
}
}
}
return 0;
}