CF1027F Session in BSU
题目大意:有n个人,每人有两个时间考试。同一个时间不能有两个人同时考试。问全部考完的最小时间。题解:二分图,考虑匈牙利+二分答案,但我太弱了导致超时。
于是考虑并查集:
比如对于2 1 5 1 7,我们可以认为有两条边,分别链接1 5和1 7。
然后分别加进去,先是:
7 1 <-> 5
这时候第一个人要在1和5间选一个,此时ans取1,而1连在5上,而不是5连在1上。
然后:
7 <-> 1 <->5
这时1不能取,因为他不是所在集的祖先元素。这时用5和7比,ans取5。
如果还有5<->7呢
这时1 5 7 构成了一个环,三个元素取三个值。
这之后如果还有一个点连在环上,那只能取不在环上的,并且要把他们并在一起;
如果两个环连在一起,那就输出-1。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 1000050 int n,e[N][2],tot,cnt,bel[2*N]; struct node { int f,t; }p[2*N]; bool cmp(node a,node b) { return a.t<b.t; } int fa[2*N]; int findfa(int x) { if(x==fa[x])return x; return fa[x]=findfa(fa[x]); } int main() { scanf("%d",&n); for(int a,b,i=1;i<=n;i++) { scanf("%d%d",&a,&b); p[++tot].f=i,p[tot].t=a; p[++tot].f=i,p[tot].t=b; } sort(p+1,p+1+tot,cmp); for(int las=-1,i=1;i<=tot;i++) { if(las!=p[i].t) { las=p[i].t; bel[++cnt]=las; } e[p[i].f][e[p[i].f][0]!=0]=cnt; } for(int i=1;i<=cnt;i++)fa[i]=i; int ans = -1; for(int i=1;i<=n;i++) { int f1 = findfa(e[i][0]),f2 = findfa(e[i][1]); if(!f1&&!f2)//已经必选 { printf("-1\n"); return 0; } if(f1>f2)swap(f1,f2); if(f1==f2||!f1||!f2) { ans=max(ans,bel[f1]);//未选->必选 fa[f1]=fa[f2]=0; }else { ans=max(ans,bel[f1]); fa[f1]=f2; } } printf("%d\n",ans); return 0; }