最小割树
关于最小割树的详细内容和证明,请看【ZJOI2016 day2讲课 无向图最小割】,这个东西自己找吧,我就不发了。。。
默默摘抄一些Gusfield算法
fa[u]在u被枚举到之前表示u所属点集的代表点,枚举到之后表示u在最小割树上的父亲。初始时所有点都属于以1为代表点的点集。从2到|V|依次枚举u,把u所在点集以u和fa[u]为源和汇拆分,所有被分到u侧的点x把fa[x]修改为u。
注意枚举之后只能把fa[x]=u或fa[x]=fa[u]的x拿来改,即属于当前点集的拿来改。这是小细节,不然会挂很惨。。。
关于跑完一次最大流之后如何确定最小割:找出从S开始在残量网络上BFS到的点和没被BFS到的点,这两个点集之间就是最小割
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 155
#define M 3005
using namespace std;
namespace runzhe2000
{
const int INF = 1<<29;
int n, m, ecnt = 1, last[N], cur[N], level[N], fa[N], fa_v[N], S, T, qx[N], arr[N*2], cnt[N*2];
struct edge{int next, to, flow;}e[M<<2];
void addedge(int a, int b, int c)
{
e[++ecnt] = (edge){last[a], b, c};
last[a] = ecnt;
e[++ecnt] = (edge){last[b], a, 0};
last[b] = ecnt;
}
void linkedge(int a, int b, int c)
{
e[++ecnt] = (edge){last[a], b, c};
last[a] = ecnt;
e[++ecnt] = (edge){last[b], a, c};
last[b] = ecnt;
}
int q[N], timer, vis[N];
bool bfs()
{
level[q[0] = S] = 1; vis[S] = ++timer;
for(int head=0, tail=1; head<tail; head++)
{
int x = q[head];
for(int i = last[x]; i; i = e[i].next)
{
int y = e[i].to;
if(vis[y] == timer || !e[i].flow) continue;
vis[y] = timer;
level[y] = level[x] + 1;
if(y == T)return true;
q[tail++] = y;
}
}
return false;
}
int dfs(int x, int flow)
{
if(x == T)return flow;
int use = 0;
for(int &i = cur[x]; i; i = e[i].next)
{
int y = e[i].to;
if(level[y] != level[x] + 1)continue;
int w = dfs(y, min(e[i].flow, flow - use));
use += w;
e[i].flow -= w;
e[i^1].flow += w;
if(use == flow)return use;
}
return use;
}
int dinic()
{
int ret = 0;
while(bfs())
{
memcpy(cur, last, sizeof(last));
ret += dfs(S, INF);
}
return ret;
}
void restore()
{
for(int i = 2; i <= ecnt; i += 2)
e[i].flow += e[i^1].flow, e[i^1].flow = 0;
}
void dfs(int x, int v, int f)
{
cnt[v]++;
for(int i = last[x]; i; i = e[i].next)
{
int y = e[i].to;
if(y == f)continue;
dfs(y, min(v, e[i].flow), x);
}
}
void init()
{
ecnt = 1;
memset(last,0,sizeof(last));
memset(cnt,0,sizeof(cnt));
}
void main()
{
int kase;
scanf("%d",&kase);
for(; kase--; )
{
init();
scanf("%d%d",&n,&m);
for(int i = 1, a, b, c; i <= m; i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
for(int i = 1; i <= n; i++) fa[i] = 1;
for(int i = 2; i <= n; i++)
{
restore();
S = i;
T = fa[i];
fa_v[i] = dinic();
for(int j = i+1; j <= n; j++) if(vis[j] == timer && fa[j] == fa[i]) fa[j] = i;
}
int Q, tot = 0;
scanf("%d",&Q);
for(int i = 1; i <= Q; i++) scanf("%d",&qx[i]), arr[++tot] = qx[i];
for(int i = 2; i <= n; i++) arr[++tot] = fa_v[i];
sort(arr+1,arr+1+tot);
tot = unique(arr+1,arr+1+tot) - arr - 1;
for(int i = 1; i <= Q; i++) qx[i] = lower_bound(arr+1,arr+1+tot,qx[i]) - arr;
for(int i = 2; i <= n; i++) fa_v[i] = lower_bound(arr+1,arr+1+tot,fa_v[i]) - arr;
memset(last,0,sizeof(last)); ecnt = 1;
for(int i = 2; i <= n; i++) linkedge(fa[i], i, fa_v[i]);
for(int i = 1; i <= n; i++) dfs(i, N*2-1, 0);
for(int i = 1; i < N*2; i++)
{
cnt[i] /= 2;
cnt[i] += cnt[i-1];
}
for(int i = 1; i <= Q; i++) printf("%d\n",cnt[qx[i]]);
puts("");
}
}
}
int main()
{
runzhe2000::main();
}