[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('
');}

  

 

 

原文地址:https://www.cnblogs.com/ylwtsq/p/13493061.html