补题向 | Session in BSU(并查集维护二分图匹配,基环树?)

Session in BSU

有n场考试,每场考试有两个参加的时间点,求参加完所有的考试的最早时间

把每个时间点看成点,每场考试的两个点相连,那么边就代表每场考试,考试的场数为边数en,参加考试的时间点为顶点数量vn

对于每个连通板块,只有三种情况

vn==en,那么刚好一个时间点参加一场考试,因此参加完所有考试的时间是此板块中所有时间点的最大值,这种情况下板块中肯定存在环

vn=en+1,有一个多余的时间点,则肯定不选最晚的时间点,即最大值,所以答案是次大值,这种情况下板块是树

vn<en,考试场数多于可选时间点,没办法参加所有考试

把每个连通板块的值求出来之后求最大值就是最终结果

使用并查集维护各个点之间关系、vn、en和最大值、次大值

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<fstream>
#include<math.h>
#include<stack>
#include<queue>
#include<bitset>
#include<utility>
#include<set>
#include<map>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const double eps=0.0000000000001;
const ll mod=998244353;
int n;
int pre[2000010];
bool f[2000010];//判断是否有环 
int vn[2000010];//点数 
int en[2000010];//边数 
int ma[2][2000010];//ma[0]存放最大值,ma[1]存放次大值 
map<int,int>id;//存放每个时间点对应id 
int find(int x){
	int r=x;
	while(pre[r]!=r){
		r=pre[r];
	}
	int i=x,j;
	while(pre[i]!=r){
		j=pre[i];
		pre[i]=r;
		i=j;
	}
	return r;
}
void update(int rx,int ry){
	//更新连通板块中最大值与次大值 
	int a=ma[0][rx];
	int b=ma[1][rx];
	int c=ma[0][ry];
	int d=ma[1][ry];
	if(b>=c){
		ma[0][ry]=a;
		ma[1][ry]=b;
	}
	else if(a>=c&&c>b){
		ma[0][ry]=a;
		ma[1][ry]=c;
	}
	else if(c>a&&a>=d){
		ma[0][ry]=c;
		ma[1][ry]=a;
	}
	else if(d>a){
		ma[0][ry]=c;
		ma[1][ry]=d;
	}
}
void add(int x,int y){
	//加边 
	int rx=find(x);
	int ry=find(y);
	en[ry]++;
	if(rx!=ry){
		pre[rx]=ry;
		vn[ry]+=(vn[rx]+1);
		en[ry]+=en[rx];
		update(rx,ry);
		if(f[rx]==1)f[ry]=1;
	}
	else{
		f[ry]=1;//如果x、y已连通,则说明有环 
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=2*n;i++){
		pre[i]=i;
	}
	int m=0;
	memset(f,0,sizeof(f));
	memset(vn,0,sizeof(vn));
	memset(en,0,sizeof(en));
	int a,b;
	int ai,bi;
	int k=1;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a,&b);
		
		map<int,int>::iterator iter;
		iter=id.find(a);
		if(iter!=id.end()){
			ai=iter->second;						
		}
		else{
			id.insert(make_pair(a,k));
			ai=k;
			ma[0][k]=a;
			ma[1][k]=0;
			k++;
		}
		iter=id.find(b);
		if(iter!=id.end()){
			bi=iter->second;			
		}
		else{
			id.insert(make_pair(b,k));
			bi=k;
			ma[0][k]=b;
			ma[1][k]=0;
			k++;			
		}
		
		add(ai,bi);
	}
	k--;
	int ans=0;
	bool flag=1;
	for(int i=1;i<=k;i++){
		if(pre[i]==i){
			if(vn[i]+1<en[i]){
				flag=0;
				break;
			}
			if(f[i]==1){
				ans=max(ans,ma[0][i]);
			}  
			else ans=max(ans,ma[1][i]);
		}
	}
	if(flag==0)printf("-1\n");
	else printf("%d\n",ans);
	return 0;
}

不知道为什么很喜欢并查集,明明上一题的dp真的想不透超down的,这一题打完ちょうきもじ

猜你喜欢

转载自blog.csdn.net/bekote/article/details/81986864