bzoj 4668
首先显然是并查集了
每次连边就是合并两个集合,最后会形成很多连通块,是个森林的结构
考虑在连边的时候加入一个权值表示这条边是第几次被加入图中的,那么每次查询的答案即为$x$到$y$路径上权值最大值
由于并查集按秩合并的复杂度是$O(log_{2}n)$,因此合并时直接按秩合并,查询时暴力向上跳即可
复杂度$O(nlog_{2}n)$
代码:
#include <cstdio> #include <cmath> #include <algorithm> using namespace std; int f[500005]; int pre[500005]; int siz[500005]; bool vis[500005]; int n,m,lastans; int ans=0; inline int findf(int x) { while(x!=f[x])x=f[x]; return x; } inline int query_find(int x) { vis[x]=1; while(x!=f[x]) { x=f[x]; vis[x]=1; } return x; } inline int query_check(int x) { while(x!=f[x]&&!vis[x]) { ans=max(ans,pre[x]); x=f[x]; } return x; } inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { // freopen("coldwar.in","r",stdin); // freopen("coldwar.out","w",stdout); n=read(),m=read(); for(register int i=1;i<=n;++i)siz[i]=1,f[i]=i; int lastans=0; int tot=0; for(register int i=1;i<=m;++i) { int typ=read(),x=read(),y=read(); x^=lastans,y^=lastans; if(typ==0) { int f1=findf(x),f2=findf(y); if(f1==f2){tot++;continue;} if(siz[f1]<siz[f2])swap(f1,f2); f[f2]=f1,siz[f1]+=siz[f2],pre[f2]=++tot; }else { ans=0; int f1=query_find(x),f2=query_check(y); if(!vis[f2]) { int tempx=x; while(tempx!=f1)vis[tempx]=0,tempx=f[tempx]; vis[f1]=0; lastans=0; }else { int tempx=x; bool flag=0; if(tempx==f2)flag=1; while(tempx!=f1) { if(!flag)ans=max(ans,pre[tempx]); vis[tempx]=0; tempx=f[tempx]; if(tempx==f2)flag=1; } vis[f1]=0; lastans=ans; } printf("%d\n",lastans); } } return 0; }