标签:
4
M 2 3
C 1 2
M 2 4
C 4 2
-1
1
/* 这个题一定要多看一下,我们并查集这样的题接触的机会并不多 要求统计两个之间的数量,普通并查集只能记录一个集合点的个数,这样就是不能实现这个功能,一个很自然的想法是开一个变量记录一下当前这个点到集合中代表元素之间的点的个数(包括这个点),设为d,只有一个元素时记为0 ①当两个集合进行合并,其代表元的深度就是另一个集合点的数量 ②当查询两个点之间的距离,一个点u到其代表元之间的点个数,就是其父节点的d加上其自身d,即d[u] + d[f[u]],为了避免多次加和就进行路径压缩,压缩完毕之后其在树上的高度值为2,可以保证最终代表元d为0,于是u的d此时为上面的值,可以维持这个性质,两点之间的数量就为(|d[u]-d[v]|-1) */ #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int n,f[30500],sz[30500],d[30500]; int findf(int x){ if(x != f[x]){ int r = findf(f[x]); d[x] += d[f[x]]; f[x] = r; } return f[x]; } int main(){ freopen("data.in","r",stdin); freopen("data.out","w",stdout); for(int i = 1;i <= 30000;i++){ f[i] = i; sz[i] = 1; } int u,v,ur,vr; char s; cin>>n; for(int i = 1;i <= n;i++){ s = getchar(); while(s != ‘M‘ && s != ‘C‘) s = getchar(); if(s == ‘M‘){ scanf("%d%d",&u,&v); u = findf(u); v = findf(v); f[u] = v; d[u] = sz[v]; sz[v] += sz[u]; }else if(s == ‘C‘){ scanf("%d%d",&u,&v); ur = findf(u); vr = findf(v); if(ur==vr)printf("%d\n",abs(d[u]-d[v])-1); else printf("-1\n"); } } return 0; }
标签:
原文地址:http://www.cnblogs.com/hyfer/p/5890046.html