[SCOI2010]連續攻擊遊戲
阿新 • • 發佈:2020-08-12
題目連結:
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');}