[CF1027F]Session in BSU[最小基環樹森林]
阿新 • • 發佈:2018-11-11
題意
有 \(n\) 門課程,每門課程可以選擇在 \(a_i\) 或者 \(b_i\) 天參加考試,每天最多考一門,問最早什麼時候考完所有課程。
\(n\leq 10^6\)。
分析
類似 [BZOJ4883]棋盤上的守衛 一題。
將每門課程對應的兩天連邊,如果課程 \(i\) 要在第 \(x\) 天考,則對應邊指向 \(x\) 。
最後有 \(n\) 天,\(n\) 條有向邊,每條邊的入度為1,構成了基環樹森林。
總時間複雜度為 \(O(nlogn)\) (離散化)。
總結:這種 \(A\) 可以選擇兩種物品之一,每種物品最多被一個人選擇的問題可以考慮基環樹。
程式碼
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;i++) typedef long double ld; inline int gi(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();} return x*f; } template<typename T> inline bool Max(T& a, const T& b) { return a < b ? a = b, true : false; } template<typename T> inline bool Min(T& a, const T& b) { return a > b ? a = b, true : false; } const int N=1e6 + 7; int n,len,ans; int V[N<<1],par[N<<1],cir[N<<1],mx[N<<1],a[N],b[N]; int getpar(int a){return par[a]==a?a:par[a]=getpar(par[a]);} int main(){ n=gi(); rep(i,1,n+n) par[i]=i; rep(i,1,n) V[++len]=a[i]=gi(),V[++len]=b[i]=gi(); sort(V+1,V+1+len); len=unique(V+1,V+1+len)-V-1; rep(i,1,n){ a[i]=lower_bound(V+1,V+1+len,a[i])-V; b[i]=lower_bound(V+1,V+1+len,b[i])-V; int f1=getpar(a[i]),f2=getpar(b[i]); if(cir[f1]&&cir[f2]) return puts("-1"),0; if(f1>f2) swap(f1,f2);Max(ans,V[f1]); if(f1==f2) {cir[f2]=1;continue;} par[f1]=f2,cir[f2]|=cir[f1]; } printf("%d\n",ans); return 0; }