E. Maximize Mex(二分图+反向求解)

E. Maximize Mex

题意:

给出n个学生,m个社团,第二行给出n个pi表示学生的潜力,第三行给出n个ci表示学生一开始所在的社团,

然后输入q,接下来输入k行查询,每次输入一个ki表示第i天第ki个学生出离开所在的社团。然后每次查询询问这一天

所能获得的最大学生序列的最大的mex,(mex是序列中第一个出现的不存在的数字eg:{1,2,4,5}的mex是3)。

思路:

将每个学生视为社团与学校之间的边,可以先将所有的查询的学生标记,然后将所有未标记的学生连入图中,

然后查询第d次的mex,接着反向逐步插入学生(将学生连接到社团),然后统计第i次的mex。

参考文章

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 300300;
struct Node{
	int v,nxt;
	Node(){}
	Node(int x,int y):v(x),nxt(y){}
}cur[maxn];
int head[maxn],ans[maxn],link[maxn],tot=0,p[maxn],c[maxn],vis[maxn],qy[maxn];
void addedge(int u,int v){
	cur[tot] = Node(v,head[u]);
	head[u] = tot++;
}
bool dfs(int u){
	for(int i = head[u];~i;i=cur[i].nxt)
	if(!vis[cur[i].v]){
		vis[cur[i].v] = 1;
		if(link[cur[i].v]==-1||dfs(link[cur[i].v])){
			link[cur[i].v] = u;
			return true;
		}
	}
	return false;
}
int main(void)
{
	int n,m,d,i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&p[i]);
	for(i=1;i<=n;i++) scanf("%d",&c[i]),c[i]+=5000;
	scanf("%d",&d);
	memset(ans,0,sizeof(ans));
	memset(vis,0,sizeof(vis));
	fill(head,head+maxn,-1);
	fill(link,link+maxn,-1);
	for(i=1;i<=d;i++){
		scanf("%d",&qy[i]);
		vis[qy[i]] = 1;
	}
	for(i=1;i<=n;i++)
	if(!vis[i]){
		addedge(p[i],c[i]);
		addedge(c[i],p[i]);
	}
	while(1){
		memset(vis,0,sizeof(vis));
		if(dfs(ans[d])) ans[d]++;
		else break;
	}
	for(i=d-1;i>=1;i--){
		addedge(p[qy[i+1]],c[qy[i+1]]);
		addedge(c[qy[i+1]],p[qy[i+1]]);
		ans[i] = ans[i+1];
		while(1){
			memset(vis,0,sizeof(vis));
			if(dfs(ans[i])) ans[i]++;
			else break;
		}
	}
	for(i=1;i<=d;i++) printf("%d\n",ans[i]);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41829060/article/details/89218042
今日推荐