题解 [CF343E] Pumping Stations

传送门

只能提出一个 \(O(炸天)\) 的非阶乘做法
先跑 \(n^2\) 次最大流求出任意两点间最大流
\(O(n^3m)\) 建出最小割树
然后建出 \(n^2\) 条边,枚举起点,拆点强制每个点经过 \(\leqslant 1\) 次跑最大流
因为最大流而且完全图所以最后每个点应该都经过了一次

艹我是 SB
建出 \(n^2\) 条边之后这是个完全图
可以直接枚举起点贪心取边
正确性考虑反证
具体可以见 @meyi 的题解
若最小割树上有一个点 \(\deg \geqslant 3\) 怎么办呢?
那么应该优先遍历边权大的点
因为最小割的是 最小 割
所以先去尽量小的会让这条比较小的被算多次
所以就先去尽量大的
复杂度 \(O(n^3m+n^3)\)

Bonus:貌似最小割树的 kruskal 重构树的 dfs 序也是答案

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#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;
bool vis[N];
vector<int> rec, tem;
vector<pair<int, int>> to[N];
int head[N], sta[N], dep[N], cur[N], dis[210][210], tem1[N], tem2[N], ecnt=1, s, t, ans;
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(int s, int t) {
	for (int i=1; i<=n; ++i) dep[i]=0;
	queue<int> q;
	dep[s]=1; cur[s]=head[s];
	q.push(s);
	while (q.size()) {
		int 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(rest, e[i].val));
			if (!tem) dep[v]=0;
			rest-=tem;
			e[i].val-=tem;
			e[i^1].val+=tem;
			if (!rest) break;
		}
	}
	return in-rest;
}

int dinic(int s, int t) {
	int ans=0; ::s=s; ::t=t;
	for (int i=2; i<=ecnt; i+=2) e[i].val+=e[i^1].val, e[i^1].val=0;
	while (bfs(s, t)) ans+=dfs(s, INF);
	return ans;
}

void gusfield(int l, int r) {
	if (l==r) return ;
	int cut=dinic(sta[l], sta[l+1]);
	to[sta[l]].pb({sta[l+1], cut});
	to[sta[l+1]].pb({sta[l], cut});
	int cnt1=0, cnt2=0;
	for (int i=l; i<=r; ++i)
		if (dep[sta[i]]) tem1[++cnt1]=sta[i];
		else tem2[++cnt2]=sta[i];
	for (int i=1; i<=cnt1; ++i) sta[l+i-1]=tem1[i];
	for (int i=1; i<=cnt2; ++i) sta[l+cnt1+i-1]=tem2[i];
	gusfield(l, l+cnt1-1);
	gusfield(l+cnt1, r);
}

void dfs1(int u, int fa, int rot, int cut) {
	dis[rot][u]=cut;
	for (auto v:to[u]) if (v.fir!=fa)
		dfs1(v.fir, u, rot, min(cut, v.sec));
}

int dfs2(int u) {
	int ans=0;
	vis[u]=1; tem.pb(u);
	int maxn=-1, maxi;
	for (int v=1; v<=n; ++v) if (!vis[v] && dis[u][v]>maxn) maxn=dis[u][v], maxi=v;
	if (~maxn) ans+=dis[u][maxi]+dfs2(maxi);
	return ans;
}

signed main()
{
	n=read(); m=read();
	memset(head, -1, sizeof(head));
	for (int i=1,u,v,w; i<=m; ++i) {
		u=read(); v=read(); w=read();
		add(u, v, w), add(v, u, 0);
		add(v, u, w), add(u, v, 0);
	}
	for (int i=1; i<=n; ++i) sta[i]=i;
	gusfield(1, n);
	for (int i=1; i<=n; ++i) dfs1(i, 0, i, INF);
	for (int i=1; i<=n; ++i) {
		tem.clear();
		for (int j=1; j<=n; ++j) vis[j]=0;
		int val=dfs2(i);
		if (val>ans) ans=val, rec=tem;
	}
	printf("%d\n", ans);
	for (auto it:rec) printf("%d ", it);
	printf("\n");
	
	return 0;
}
posted @ 2022-06-11 21:15  Administrator-09  阅读(1)  评论(0编辑  收藏  举报