【并查集】Codeforces1027F Session in BSU

本文探讨了一种算法问题,即如何安排最少的天数来完成一系列考试,每场考试可以在两个指定的日子之一进行。文章提供了详细的算法分析,包括如何构建图论模型,并通过联通块分析得出最优解的方法。

题意:

给出n场考试,每场考试有2天可以通过(第aiaibibi天)。每天最多参加一场考试,现在要求所有考试全部通过的最小天数。


分析:

可以把每天看作一个点,每次考试看作一条边。现在要每条边选择一个点,把每个联通块分别考虑,很容易发现:
如果是树(n=m+1),那么只有1个点不用选,为了最优性,肯定不选最大的一个。
如果是基环外向树(n=m),那么所有点都必须选。
如果n<mn<m,则无法满足。

所以只需要维护每个联通块的最大值,次大值即可,顺便判断一下这个联通块是否刚好只有1个环。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 2000010
#define MOD 998244353 
using namespace std;
typedef long long ll;
int n,u,v;
int val[MAXN];
pair<int,int> l[MAXN];
int fa[MAXN];
bool spe[MAXN];
int maxv[MAXN],secv[MAXN];
int c[5];
int get_fa(int x){
    if(fa[x]==0)
        return x;
    fa[x]=get_fa(fa[x]);
    return fa[x];
}
bool merge(int u,int v){
    u=get_fa(u);
    v=get_fa(v);
    if(u==v){
        if(spe[u]==1)
            return 0;
        spe[u]=1;
    }
    else{
        fa[u]=v;
        spe[v]=max(spe[v],spe[u]);
        c[0]=maxv[v];
        c[1]=maxv[u];
        c[2]=secv[v];
        c[3]=secv[u];
        sort(c,c+4);
        maxv[v]=c[3];
        secv[v]=c[2];
    }
    return 1;
}
int main(){
    SF("%d",&n);
    for(int i=1;i<=n;i++){
        SF("%d%d",&u,&v);
        l[i]=make_pair(u,v);
        val[i*2]=u;
        val[i*2-1]=v;
    }
    sort(val+1,val+1+2*n);
    int cnt=unique(val+1,val+1+2*n)-val-1;
    for(int i=1;i<=n;i++){
        l[i].first=lower_bound(val+1,val+1+cnt,l[i].first)-val;
        l[i].second=lower_bound(val+1,val+1+cnt,l[i].second)-val;
        //PF("{%d %d}",l[i].first,l[i].second);
    }
    for(int i=1;i<=cnt;i++){
        maxv[i]=val[i];
        secv[i]=0;
    }
    for(int i=1;i<=n;i++){
        if(merge(l[i].first,l[i].second)==0){
            PF("-1");
            return 0;
        }
    }
    int ans=0;
    for(int i=1;i<=cnt;i++)
        if(i==get_fa(i)){
            if(spe[i]==1)
                ans=max(ans,maxv[i]);
            else
                ans=max(ans,secv[i]);
        }
    PF("%d",ans);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值