一、题目
二、解法
把天数作为点,把考试作为边,问题就是每个点和它的某个边绑定,要求所有边都用完的最小点编号。
对于一个连通块,如果边数 > > >点数就无解,如果边数 < < <点数那么就可以空出来一个点(以这个点为根,不选它),如果边数 = = =点数一定有解,但是所有点都必须选,第二种情况需要点编号次大值,第一种情况需要点编号最大值,用并查集维护一下就行了,本题要写离散化。
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 1000005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,ans,a[M],b[M];
int q[2*M],fa[2*M],mx[2*M][2],cnt[2*M],siz[2*M];
int find(int x)
{
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int u,int v)
{
int x=find(u),y=find(v);
if(x==y)
{
cnt[x]++;
return ;
}
fa[x]=y;siz[y]+=siz[x];
cnt[y]+=cnt[x]+1;
if(mx[y][0]<mx[x][0])
{
mx[y][1]=mx[y][0];
mx[y][0]=mx[x][0];
if(mx[y][1]<mx[x][1])
mx[y][1]=mx[x][1];
}
else if(mx[y][1]<mx[x][0])
mx[y][1]=mx[x][0];
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();b[i]=read();
q[++m]=a[i];q[++m]=b[i];
}
sort(q+1,q+1+m);
m=unique(q+1,q+1+m)-q-1;
for(int i=1;i<=m;i++)
{
fa[i]=i;siz[i]=1;
mx[i][0]=i;
}
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(q+1,q+1+m,a[i])-q;
b[i]=lower_bound(q+1,q+1+m,b[i])-q;
merge(a[i],b[i]);
}
for(int i=1;i<=m;i++)
if(i==find(i))
{
if(cnt[i]>siz[i])
{
puts("-1");
return 0;
}
if(cnt[i]==siz[i])
ans=max(ans,mx[i][0]);
else
ans=max(ans,mx[i][1]);
}
printf("%d\n",q[ans]);
}