题解 社会黄油飞

传送门

看怎么处理这个式子
赛时思路是枚举点集大小然后二分网络流check
于是就不会了

其实不用枚举点集大小,直接移项,有

\[e(s)-lim|s|>-lim \]

其中 \(e(s)\) 为 s 的导出子图大小
发现选了一条边就必须选对应的两个端点,跑最大权闭合子图即可
但是直接跑的话会把 \(s=\varnothing\) 算进去,这样是不合法的
所以要枚举并钦定选一个点
这样的话要跑 \(n\) 次网络流,复杂度就假了
发现每次删除的边只有一条,考虑退流
对于一条边 \((u, v)\),从 \(t\)\(v\) 跑最大流,从 \(u\)\(s\) 跑最大流
再将这条边的流量清空即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, lim;
pair<int, int> g[N];
int head[N], dep[N], cur[N], id[N], ecnt=1, s, t, ans=0;
struct edge{int to, next, val;}e[N<<1];
inline void add(int s, int t, int w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}

bool bfs() {
	memset(dep, 0, sizeof(dep));
	queue<int> q;
	cur[s]=head[s]; dep[s]=1;
	q.push(s);
	int u;
	while (q.size()) {
		u=q.front(); q.pop();
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (e[i].val && !dep[v]) {
				dep[v]=dep[u]+1;
				cur[v]=head[v];
				if (v==t) return 1;
				q.push(v);
			}
		}
	}
	return 0;
}

int dfs(int u, int in) {
	if (u==t||!in) return in;
	int rest=in, tem;
	for (int i=cur[u],v; ~i; cur[u]=i=e[i].next) {
		v = e[i].to;
		if (e[i].val && dep[v]==dep[u]+1) {
			tem=dfs(v, min(e[i].val, rest));
			if (!tem) dep[v]=0;
			e[i].val-=tem;
			e[i^1].val+=tem;
			rest-=tem;
			if (!rest) break;
		}
	}
	return in-rest;
}

int dinic() {
	while (bfs()) ans+=dfs(s, INF);
	return ans;
}

int pushback(int u, int in) {
	//cout<<"pushback: "<<u<<' '<<in<<endl;
	if (u==s||!in) return in;
	int rest=in, tem;
	for (int i=head[u],v; ~i; i=e[i].next) if (i&1 && e[i].val) {
		v = e[i].to;
		//cout<<"v: "<<v<<endl;
		tem=pushback(v, min(rest, e[i].val));
		e[i].val-=tem;
		e[i^1].val+=tem;
		rest-=tem;
		if (!rest) break;
	}
	return in-rest;
}

signed main()
{
	freopen("socialbutterfly.in", "r", stdin);
	freopen("socialbutterfly.out", "w", stdout);

	n=read(); m=read(); lim=read(); s=n+m+1; t=n+m+2;
	memset(head, -1, sizeof(head));
	for (int i=1; i<=m; ++i) g[i].fir=read(), g[i].sec=read();
	for (int i=1; i<=m; ++i) {
		add(s, i, 1), add(i, s, 0);
		add(i, g[i].fir+m, INF), add(g[i].fir+m, i, 0);
		add(i, g[i].sec+m, INF), add(g[i].sec+m, i, 0);
	}
	for (int i=1; i<=n; ++i) id[i]=ecnt+1, add(i+m, t, lim), add(t, i+m, 0);
	for (int i=1; i<=n; ++i) {
		//cout<<"i: "<<i<<endl;
		ans-=e[id[i]^1].val;
		pushback(i+m, e[id[i]^1].val);
		e[id[i]].val=0; e[id[i]^1].val=0;
		int t=dinic();
		//cout<<"t: "<<t<<endl;
		if (m-t>0) {puts("Yes"); return 0;}
		e[id[i]].val=lim;
	}
	puts("No");
	
	return 0;
}
posted @ 2022-02-15 10:25  Administrator-09  阅读(1)  评论(0编辑  收藏  举报