传送门
题目大意:每个人都有一个潜力值和所属的俱乐部,但是呢,学校每天要一个人滚出俱乐部,然后在所有的俱乐部各选一人,组成一个序列求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;
}