bnuoj 51275 并查集按深度合并建树
道路修建 Large
Time Limit: 5000ms
Memory Limit: 131072KB
64-bit integer IO format: %lld Java class name: Main无向图初始有个点,从到依次标号,但是没有边,
接下来有次操作,从到依次标号,你需要对每种操作输出相应的结果,操作分为两种:
输入格式 |
操作说明 |
输出结果 |
0_u_v |
加入一条连接标号为和标号为的点的边。 |
输出加边后图中连通块的个数。 |
1_u_v |
查询标号为和标号为的点之间是否连通。 |
如果连通,输出,表示最早在第次操作后标号为和标号为的点之间连通,否则输出。 |
(输入格式中的下划线‘_’表示实际输入文件中的空格)
Input
第一行是一个正整数,表示测试数据的组数,
对于每组测试数据,
第一行包含两个整数、,
接下来行,每行是个整数、、,请注意所给的、均是经过加密的,
解密方式是、 ,其中表示上一次操作的输出结果,
初始,保证,解密后且。
Output
对于每组测试数据,
输出行,每行包含一个整数,表示操作的输出结果。
Sample Input
1 4 7 0 1 2 1 1 0 0 1 3 0 0 1 1 0 1 0 1 7 1 0 5
Sample Output
3 0 2 2 3 1 6
Source
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,m; int fa[maxn],val[maxn]; int rk[maxn]; int op,u,v; int vis[maxn]; int find(int x) { return fa[x]==x?x:find(fa[x]); } int main() { freopen("in.txt","r",stdin); int T;cin>>T; while(T--){ scanf("%d%d",&n,&m); REP(i,1,n) fa[i]=i,val[i]=0; REP(i,1,n) rk[i]=1; REP(i,1,n) vis[i]=0; int lans=0,cnt=n; REP(i,1,m){ scanf("%d%d%d",&op,&u,&v); u^=lans;v^=lans; int x=find(u),y=find(v); if(op==0){ if(x!=y){ if(rk[x]>rk[y]) swap(x,y); fa[x]=y; rk[y]=max(rk[y],rk[x]+1); val[x]=i; cnt--; } lans=cnt; } else{ if(x!=y) lans=0; else{ int t=u; vis[x]=i; while(fa[t]!=t) vis[t]=i,t=fa[t]; int lca=x; t=v; while(fa[t]!=t){ if(vis[t]==i){ lca=t;break; } t=fa[t]; } lans=0; while(u!=lca) lans=max(lans,val[u]),u=fa[u]; while(v!=lca) lans=max(lans,val[v]),v=fa[v]; } } printf("%d\n",lans); } } return 0; }
没有AC不了的题,只有不努力的ACMER!