(CodeForce) E. Maximize Mex (匈牙利)

传送门

题目大意:每个人都有一个潜力值和所属的俱乐部,但是呢,学校每天要一个人滚出俱乐部,然后在所有的俱乐部各选一人,组成一个序列求mex,就是组成的序列中没出现的最小自然数。

解题思路:我们可以建一个潜力值和俱乐部的二分图,我们潜力值从低到高匹配,如果有一个潜力值无法被匹配,那这次所求的mex不就是它了嘛。所有我们可以将查询的序列倒着处理,从后往前逐个往里面加人,连边。每次跑匈牙利去尝试匹配就行了,从后往前肯定是一个不降序列了。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=5e3+5;
int match[maxn<<2],belone[maxn],po[maxn];
bool vis[maxn<<2],pd[maxn];
vector<int> mp[maxn<<2];
il bool dfs(int x){
	for(int i=0;i<(int)mp[x].size();++i){
		if(!vis[mp[x][i]]){
			vis[mp[x][i]]=1;
			if(match[mp[x][i]]==-1 || dfs(match[mp[x][i]])){
				match[mp[x][i]]=x;
				return 1;
			}
		}
	}
	return 0;
}
int n,m,k,qu[maxn],ans[maxn];
int main(){
	std::ios::sync_with_stdio(0);
	ms(match,-1); //有0置成-1
	cin>>n>>m;
	for(int i=1;i<=n;++i)	cin>>po[i]; //潜力值
	for(int i=1;i<=n;++i)	cin>>belone[i]; //属于哪个俱乐部
	cin>>k;
	for(int i=1;i<=k;++i)	cin>>qu[i],pd[qu[i]]=1; 
	for(int i=1;i<=n;++i){ //没有被踢的同学先连边
		if(!pd[i]){
			mp[po[i]].pb(belone[i]+m);
			mp[belone[i]+m].pb(po[i]); 
		} 
	}
	int j=0;
	for(int i=k;i>=1;--i){
		for(;j<m;++j){ //先跑匈牙利
			ms(vis,0);
			if(!dfs(j))	break;
		}
		ans[i]=j; 
		mp[po[qu[i]]].pb(belone[qu[i]]+m); //加人连边
		mp[belone[qu[i]]+m].pb(po[qu[i]]);
	}
	for(int i=1;i<=k;++i)	cout<<ans[i]<<endl; 
	return 0;
}







 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值