1. 程式人生 > >[bzoj1854][Scoi2010]遊戲【並查集】【貪心】

[bzoj1854][Scoi2010]遊戲【並查集】【貪心】

【題目描述】

Description

lxhgww最近迷上了一款遊戲,在遊戲裡,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxhgww遇到了終極boss,這個終極boss很奇怪,攻擊他的裝備所使用的屬性值必須從1開始連續遞增地攻擊,才能對boss產生傷害。也就是說一開始的時候,lxhgww只能使用某個屬性值為1的裝備攻擊boss,然後只能使用某個屬性值為2的裝備攻擊boss,然後只能使用某個屬性值為3的裝備攻擊boss……以此類推。 現在lxhgww想知道他最多能連續攻擊boss多少次?

Input

輸入的第一行是一個整數N,表示lxhgww擁有N種裝備 接下來N行,是對這N種裝備的描述,每行2個數字,表示第i種裝備的2個屬性值

Output

輸出一行,包括1個數字,表示lxhgww最多能連續攻擊的次數。

Sample Input

3
1 2
3 2
4 5

Sample Output

2

HINT

【資料範圍】
對於30%的資料,保證N < =1000
對於100%的資料,保證N < =1000000

Source

Day1

【題解】

    第一眼看這道題以為是迭代的網路流,但有更妙的貪心演算法。

    考慮並查集,把每個裝備當做一條邊,如果存在一個聯通塊是樹,那麼一定是剩下編號最大的一個不選,如果不是樹,那麼能全部去完。

    合併時,如果是兩棵樹,剩下編號大的,取編號小的。否則都能取完。

    複雜度 O(n α n)

/* --------------
    user Vanisher
    problem bzoj-1854
----------------*/
# include <bits/stdc++.h>
# define 	ll 		long long
# define 	N 		10010
using namespace std;
int read(){
	int tmp=0, fh=1; char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
	return tmp*fh;
}
int f[N],n,u,v,can[N];
int dad(int u){
	if (f[u]==u) return u;
		else return f[u]=dad(f[u]);
}
int main(){
	n=read();
	for (int i=1; i<=N-1; i++) f[i]=i;
	for (int i=1; i<=n; i++){
		u=read(), v=read();
		u=dad(u), v=dad(v);
		if (u==v) can[u]=true;
		else {
			if (u>v) swap(u,v);
			if (can[u]==true) can[v]=true;
				else can[u]=true;
			f[u]=v;
		}
	}
	for (int i=1; i<=N-1; i++)
		if (can[i]==false) {
			printf("%d\n",i-1);
			return 0;
		}
	return 0;
}