codeforces1139E. Maximize Mex 二分图匹配

There are n students and m clubs in a college. The clubs are numbered from 1 to m. Each student has a potential pi and is a member of the club with index ci . Initially, each student is a member of exactly one club. A technical fest starts in the college, and it will run for the next d days. There is a coding competition every day in the technical fest.
Every day, in the morning, exactly one student of the college leaves their club. Once a student leaves their club, they will never join any club again. Every day, in the afternoon, the director of the college will select one student from each club (in case some club has no members, nobody is selected from that club) to form a team for this day’s coding competition. The strength of a team is the mex of potentials of the students in the team. The director wants to know the maximum possible strength of the team for each of the coming d days. Thus, every day the director chooses such team, that the team strength is maximized.
The mex of the multiset S is the smallest non-negative integer that is not present in S. For example, the mex of the {0,1,1,2,4,5,9} is 3, the mex of {1,2,3} is 0 and the mex of ∅ (empty set) is 0.

Input
The first line contains two integers n and m (1≤m≤n≤5000), the number of students and the number of clubs in college.
The second line contains n integers p1 ,p2 ,…,pn (0≤pi <5000), where pi is the potential of the i-th student.
The third line contains n integers c1 ,c2 ,…,cn (1≤ci ≤m), which means that i-th student is initially a member of the club with index ci .
The fourth line contains an integer d(1≤d≤n), number of days for which the director wants to know the maximum possible strength of the team.
Each of the next d lines contains an integer ki (1≤ki ≤n), which means that ki -th student lefts their club on the i-th day. It is guaranteed, that the ki -th student has not left their club earlier.

Output
For each of the d days, print the maximum possible strength of the team on that day.

Examples
Input

5 3
0 1 2 2 0
1 2 2 3 2
5
3
2
4
5
1

Output

3
1
1
1
0

Input

5 3
0 1 2 2 1
1 3 2 3 2
5
4
2
3
5
1

Output

3
2
2
1
0

Input

5 5
0 1 2 4 5
1 2 3 4 5
4
2
3
5
4

Output

1
1
1
1

现在有N个学生和M个社团,每个学生都有他自己潜能P,然后学校要举办一个比赛持续d天,在这d天中,每天都有一个学生离开社团,离开后不再加入任何社团,现在每天要从每个还有人的社团中挑选一个人,组成一支队伍,没有人的社团不选择,求每天组成队伍的特征值。这个特征值的定义如下,由队员潜能组成的集合中,从0起,第一个没有出现在集合中的正整数。
这个题不难看出来就是把潜能和社团建个二分图,从0起判断那个潜能值没有匹。假设今天走了一个潜能为P1的学生,正好是前一天被选中的人,因为删除P1不影响P1之前的匹配,如果P1在是能匹配,那么P1不在了也能匹配,所以就需要清空包括P1以后的潜能值重新匹配。考虑最坏情况,就是每次都走一个潜能为0的人,这样重新匹配的次数是拉满的,所以每天删一个人重新匹配一遍复杂度太高,需要转化问题。
我们可以把删除转化为添加,也就是说倒着求,先求除最后一天的特征值,再由最后一天倒推回第一天。从所有要走的学生都走光了之后,求出一个特征值,这就是最后一天的特征值。那么前一天就是向社团中加入今天走的人,再匹配一遍。因为是加入边,所以只会产生新的匹配,就是说我们只需要从今天的特征值开始向上找。


#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>

#define MAXN 10015
#define clubSTAR 5005
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
struct Edge{
    int to,cap,rev;
};

int store[5005];
int P[5005],C[5005],K[5005];
bool ini[5005];
bool used[MAXN];
int match[MAXN];
vector<int> adj[MAXN];
inline void addEdge(int u,int v);
int bin_match();
bool dfs(int v);
int main(){
    int N,M;
    scanf("%d %d",&N,&M);
    rep(i,1,N+1)
        scanf("%d",&P[i]);
    rep(i,1,N+1)
        scanf("%d",&C[i]);
    //student
    int d;
    scanf("%d",&d);
    mem(ini,true);
    rep(i,1,d+1){
        scanf("%d",&K[i]);
        ini[K[i]]=false;
    }

    //add edge
    rep(i,1,N+1){
        if(ini[i])
            addEdge(P[i],C[i]+clubSTAR);
    }

    //get mex
    store[d]=bin_match();
    drep(i,d,2){
        int stu=K[i];
        addEdge(P[stu],C[stu]+clubSTAR);
        rep(j,store[i],M+1){
            mem(used,false);
            if(!dfs(j)){
                store[i-1]=j;
                break;
            }
        }
    }

    //output
    rep(i,1,d+1){
        printf("%d\n",store[i]);
    }

    re 0;
}
inline void addEdge(int u,int v){
    adj[u].Push(v);
    adj[v].Push(u);
}
int bin_match(){
    mem(match,-1);
    rep(i,0,MAXN){
        if(match[i]<0){
            mem(used,false);
            if(!dfs(i))
                re i;
        }
    }
}
bool dfs(int v){
    used[v]=true;
    rep(i,0,getLen(adj,v)){
        int u=adj[v][i],matched=match[u];
        if(matched<0 || !used[matched] && dfs(matched)){
            match[v]=u;
            match[u]=v;
            re true;
        }
    }
    re false;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值