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