「题解」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;
}