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;
}

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/9834433.html
今日推荐