do_while_true

一言(ヒトコト)

「题解」Codeforces 1721F Matching Reduction

不弱于二分图最大匹配,那跑个网络流先。

直接考虑删点使得最大匹配恰好 \(-1\) 似乎有些困难,考虑利用 König 定理:二分图最小点覆盖大小等于最大匹配大小,删点使得最小点覆盖恰好 \(-1\)

先求出这个最小点覆盖。可以直接套用 König 定理的构造性证明:对于每个右边每个失配点,尝试走“一条匹配,一条没匹配...”这样交替出现的路径,然后将所有走到的点都打上标记,称之为标记点。则左侧的标记点和右侧的未标记点组成了最小点覆盖。

求出最小点覆盖之后,发现任意删掉一个最小点覆盖中的点即可使得最小点覆盖恰好 \(-1\)

  • 设原先最小点覆盖大小为 \(s\),删去点 \(x\) 后,原先最小点覆盖方案中去掉 \(x\) 即为一个合法的点覆盖,所以删点后最小点覆盖 \(\leq s-1\)
  • 删点后最小点覆盖不会 \(<s-1\),否则将 \(x\) 加入这个点覆盖方案,是删点前的一组合法点覆盖,其大小 \(<s\),与 \(s\) 是最小点覆盖大小矛盾。

所以遇到一操作直接删掉最小点覆盖中的任意一个点即可。

时间复杂度 \(\mathcal{O}(m\sqrt n+q)\)

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<random>
#include<assert.h>
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n';
#define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n';
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<ll,ll>pll;
typedef pair<int,ll>pil;
typedef vector<int>vi;
typedef vector<ll>vll;
typedef vector<pii>vpii;
typedef vector<pil>vpil;
template<typename T>T cmax(T &x, T y){return x=x>y?x:y;}
template<typename T>T cmin(T &x, T y){return x=x<y?x:y;}
template<typename T>
T &read(T &r){
	r=0;bool w=0;char ch=getchar();
	while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
	while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
	return r=w?-r:r;
}
template<typename T1,typename... T2>
void read(T1 &x,T2& ...y){read(x);read(y...);}
#define flh fflush(stdout)
const int N=1000010;
const int inf=0x7fffffff;
int n1,n2,m,q;
int ent=1,tot,S,T;
int dis[N],head[N],cur[N];
int eu[N],ev[N],eid[N];
int blo[N],evis[N];
ll sum=0;
int vis[N];
struct Edge{
	int nxt,to,fl;
}e[N<<1];
inline void add(int x,int y,int z){
	e[++ent]={head[x],y,z};head[x]=ent;
	e[++ent]={head[y],x,0};head[y]=ent;
}
int bfs(){
	for(int i=1;i<=tot;i++)cur[i]=head[i],dis[i]=0;
	queue<int>q;q.push(S);dis[S]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].nxt){
			int v=e[i].to,fl=e[i].fl;
			if(fl){
				if(!dis[v]){
					dis[v]=dis[x]+1;
					q.push(v);
				}
			}
		}
	}
	return dis[T]>0;
}
int dfs(int x,int mxfl){
	if(x==T)return mxfl;
	int flow=0;
	for(int i=cur[x];i&&flow<mxfl;i=e[i].nxt){
		cur[x]=i;
		int v=e[i].to;
		if(dis[v]==dis[x]+1){
			int fl=dfs(v,min(e[i].fl,mxfl-flow));
			flow+=fl;e[i].fl-=fl;e[i^1].fl+=fl;
		}
	}
	return flow;
}
int dinic(){
	int mxfl=0;
	while(bfs())mxfl+=dfs(S,inf);
	return mxfl;
}
void dfs(int x){
	if(vis[x])return ;
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt)if(!e[i].fl)dfs(e[i].to);
}
signed main(){
	#ifdef do_while_true
//		assert(freopen("data.in","r",stdin));
//		assert(freopen("data.out","w",stdout));
	#endif
	read(n1);read(n2);read(m);read(q);
	S=n1+n2+1;tot=T=S+1;
	for(int i=1;i<=n1;i++)add(S,i,1);
	for(int i=1;i<=n2;i++)add(i+n1,T,1);
	for(int i=1;i<=m;i++){
		int x,y;read(x,y);
		eu[i]=x;ev[i]=n1+y;eid[i]=ent+1;
		add(x,n1+y,1);
	}
	dinic();
	for(int i=1;i<=m;i++){
		if(!e[eid[i]].fl){
			blo[eu[i]]=blo[ev[i]]=i;
			sum+=i;
			evis[i]=1;
		}
	}
	for(int i=n1+1;i<=n1+n2;i++)
		if(!blo[i])
			dfs(i);
	vi vec;
	for(int i=1;i<=n1;i++)if(vis[i])vec.pb(i);
	for(int i=n1+1;i<=n1+n2;i++)if(!vis[i])vec.pb(i);
	while(q--){
		int op;read(op);
		if(op==1){
			puts("1");
			int x=vec.back();vec.pop_back();
			if(x<=n1)cout << x << '\n';
			else cout << -(x-n1) << '\n';
			evis[blo[x]]=0;
			sum-=blo[x];
			cout << sum << '\n';
		}
		else{
			vi eg;
			for(int i=1;i<=m;i++)if(evis[i])eg.pb(i);
			cout << eg.size() << '\n';
			for(auto i:eg)cout << i << ' ';
			puts("");
		}
		flh;
	}
    #ifdef do_while_true
		cerr<<'\n'<<"Time:"<<1.0*clock()/CLOCKS_PER_SEC*1000<<" ms"<<'\n';
	#endif
	return 0;
}
posted @ 2022-09-29 14:48  do_while_true  阅读(23)  评论(0编辑  收藏  举报