并查集的一般操作 ①
Rt
题目背景
A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。
题目描述
给出A地区的村庄数N,和公路数M,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)
输入输出格式
输入格式:
第1行两个正整数N,M
下面M行,每行3个正整数x, y, t,告诉你这条公路连着x,y两个村庄,在时间t时能修复完成这条公路。
输出格式:
如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1,否则输出最早什么时候任意两个村庄能够通车。
输入:
4 4
1 2 6
1 3 4
1 4 5
4 2 3
输出:
5
分析:
首先读题发现是一道并查集的 水 题,先对t从小到大排序,然后挨个合并,但怎么判断合并全了?
这时我们需要一个很巧妙的方法
可以建一个val[ ]=1;然后集合合并时val相加
详见代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> using namespace std; int n,m; int val[1000010]; //并查集 struct b { int par[1000100]; inline void ih(){for(int i=1;i<=n;++i) {par[i]=i;val[i]=1;}} inline int f (int x){return par[x]=(par[x]==x)?x:f(par[x]);} inline int u (int x,int y) { val[f(x)]+=val[f(y)];//对祖先的val操作 par[f(y)]=f(x); } inline int get_val (int x) { return val[f(x)]; } }s; struct data { int x,y,t; friend bool operator < (data a,data b) { return a.t<b.t; } }a[10100000]; int sum=2,ans; bool flag=0; int main() { freopen("in","r",stdin); scanf("%d%d",&n,&m); scanf("%d%d%d",&a[0].x,&a[0].y,&a[0].t); for(int i=1;i<m;++i) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t); } sort(a,a+m); s.ih(); for(int i=0;i<m;++i) { if(s.f(a[i].x)!=s.f(a[i].y)) { s.u(a[i].x,a[i].y); ans=a[i].t; if(s.get_val(a[i].x)==n) { printf("%d",ans); flag=1; break; } } } if(flag==0) { printf("-1"); } }