1. 程式人生 > 實用技巧 >[SCOI2010]連續攻擊遊戲

[SCOI2010]連續攻擊遊戲

題目連結:

  P1640[SCOI2010]連續攻擊遊戲

solution:

  此題有一個神奇的性質.首先,對這n個二元組$(x,y)$進行建雙向邊,形成若干個聯通圖.對於每個聯通圖,如果形成一棵樹,那麼根據貪心,最大值不可取.如果存在環,則整個集合可取.並查集維護即可.

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define mod K
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
ll n;
ll maxx;
const ll maxn=1e5;
ll f[maxn];
bool vis[maxn];
inline ll getf(ll x){return f[x]==x?x:f[x]=getf(f[x]);}
inline void merge(ll x,ll y){f[getf(x)]=getf(y);}
inline bool check(ll x,ll y){return getf(x)==getf(y);}
ll ans;
int main(){	
	n=read();
	for(R ll i=1;i<=10000;i++) f[i]=i;
	for(R ll i=1,x,y;i<=n;i++){
		x=read();y=read();
		if(x>y) swap(x,y);
		maxx=max(maxx,max(x,y));
		if(vis[getf(y)]||vis[getf(x)]||check(x,y)){
			merge(x,y);
			vis[getf(x)]=vis[getf(y)]=true;
		}
		else merge(x,y);
	}
	for(R ll i=1;i<=maxx;i++){
		if(getf(i)!=i||vis[getf(i)]) ans=i;
		else break;
	}
	writeln(ans);
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}