zoukankan      html  css  js  c++  java
  • [Codeforces 1027 F] Session in BSU [并查集维护二分图匹配问题]

    题面

    传送门

    思路

    真是一道神奇的题目呢

    题目本身可以转化为二分图匹配问题,要求右半部分选择的点的最大编号最小的一组完美匹配

    注意到这里左边半部分有一个性质:每个点恰好连出两条边到右半部分

    那么我们可以利用这个性质

    考虑一个左边的点和它右边联通的两个点,发现这两个点只能选择一个和这个左边的点匹配

    那么我们考虑把这个点点匹配的模型转化成点边匹配

    我们在同一个左边点连的两个右边点之间连边,那么问题就变成了一个点和一条相邻的边匹配,求完美匹配的问题了

    而这个问题,我们显然可以用并查集来很好的解决

    考虑一个联通块,如果联通块中边数大于点数,那么可以直接输出-1,因为此时边代表的是原题中需要满足的那个东西(考试),而边比点多就一定无解了

    如果边数等于点数,那么显然这个联通块中做出最大值贡献的点应该是编号最大的那个。这种情况下我们会得到一棵基环树,每个边恰好有一个点和它匹配

    如果边数小于点数,那么这个联通块肯定是一个树,那么此时对答案的贡献就是联通块中的次大值了,因为可以以最大值为根,不选根,剩下的每个点匹配连接它和它父亲的那条边

    用并查集维护联通块内部的点数、边数、最大值和次大值,最后扫一遍,取所有联通块的最大贡献的最大值即可

    Code

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cassert>
    #define ll long long
    using namespace std;
    inline int read(){
    	int re=0,flag=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){
    		if(ch=='-') flag=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    	return re*flag;
    }
    int f[2000010],maxn[2000010],sec[2000010],cnte[2000010],cntn[2000010];
    inline int find(int x){return ((f[x]==x)?x:f[x]=find(f[x]));}
    inline void join(int x,int y){
    	x=find(x);y=find(y);
    	if(x==y){
    		cnte[x]++;return;//注意这里也需要加一条边
    	}
    	f[x]=y;cnte[y]+=cnte[x]+1;cntn[y]+=cntn[x];
    	int tmp[4];
    	tmp[0]=maxn[x];tmp[1]=sec[x];tmp[2]=maxn[y];tmp[3]=sec[y];
    	sort(tmp,tmp+4);
    	maxn[y]=tmp[3];sec[y]=tmp[2];
    }
    struct node{
    	int val,num,pos;
    }a[2000010];
    int n,cnt;
    inline bool cmp1(node l,node r){
    	return l.val<r.val;
    }
    inline bool cmp2(node l,node r){
    	return l.num<r.num;
    }
    int main(){
    	n=read();int i,j;
    	for(i=1;i<=n;i++) a[i].val=read(),a[i+n].val=read(),a[i].num=i,a[i+n].num=i+n;
    	sort(a+1,a+(n<<1)+1,cmp1);
    	for(i=1;i<=(n<<1);i++){
    		j=i;
    		while(a[i+1].val==a[i].val&&i<(n<<1)) i++;
    		cnt++;f[cnt]=cnt;cnte[cnt]=0;cntn[cnt]=1;maxn[cnt]=a[i].val;sec[cnt]=0;
    		while(j<=i) a[j].pos=cnt,j++;
    	}
    	sort(a+1,a+(n<<1)+1,cmp2);
    	for(i=1;i<=n;i++){
    		join(a[i].pos,a[i+n].pos);
    	}
    	int ans=0;
    	for(i=1;i<=cnt;i++){
    		if(f[i]==i){
    			if(cnte[i]>cntn[i]){
    				puts("-1");return 0;
    			}
    			if(cnte[i]==cntn[i]) ans=max(ans,maxn[i]);
    			if(cnte[i]<cntn[i]) ans=max(ans,sec[i]);
    		}
    	}
    	cout<<ans<<'
    ';
    }
    
  • 相关阅读:
    Linux下nginx 的常用命令
    Mybatis generator 自动生成代码(2)
    Android Retrofit2 网路编程
    Android webView输出自定义网页
    Android Studio OkHttpClient使用
    Android Studio SVN使用
    Android Toolbar的使用 顶部标题栏+后退键
    Android DrawLayout + ListView 的使用(一)
    RabbitMQ配置与安装
    Struts2拦截器
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9501293.html
Copyright © 2011-2022 走看看