1. 程式人生 > >並查集的一般操作 ①

並查集的一般操作 ①

flag get 能夠 clas tro lap clu oid operator

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相加

詳見代碼:

技術分享圖片
#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"); } }
View Code

並查集的一般操作 ①