裸的最小割樹(分治最小割是啥,能喫嗎)
簡單的看了一下最小割樹的建樹方法
首先以1爲根建立星型(菊花)樹
然後對於2到n每個節點:
跑它(S)和它父親(T)的最小割
得出來的最小割即爲樹上該條邊的權值
然後找到比該節點編號大的節點,如果它的父親爲T且它在S集中,那麼把它的父親置爲S
搞下一個節點
複雜度就是最小割*n
然後樹上兩點間路徑的瓶頸即爲兩點間最小割(好像可以查詢的樣子哎)
於是答案就是最小割樹的邊集的值的集合的大小(一口氣說完真爽)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
using namespace std;
typedef long long ll;
const int inf=1e9;
const int N=850+5;
const int M=8500+5;
struct Edge{int to,next,v,c;}e[M<<1];
int head[N],cnt=1;
void ins(int u,int v,int w){e[++cnt]=(Edge){v,head[u],w,w};head[u]=cnt;}
void insert(int u,int v,int w){ins(u,v,w);ins(v,u,w);}
int d[N];
bool bfs(int s,int t){
mmt(d,-1);d[s]=0;queue<int>q;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
tra(i,u)
if(e[i].v&&d[e[i].to]==-1){
d[e[i].to]=d[u]+1;
q.push(e[i].to);
}
}
return d[t]!=-1;
}
int dfs(int u,int f,int t){
if(u==t)return f;
int flow=0,w;
tra(i,u)
if(e[i].v&&d[e[i].to]==d[u]+1){
w=dfs(e[i].to,min(e[i].v,f-flow),t);
e[i].v-=w;e[i^1].v+=w;flow+=w;
if(flow==f)return f;
}
if(!flow)d[u]=-1;
return flow;
}
int dinic(int s,int t){int ans=0;while(bfs(s,t))ans+=dfs(s,inf,t);return ans;}
bool g[N][N];
int fa[N],vis[N];
set<int>s;
void dfs(int u,int T){
vis[u]=T;
tra(i,u)
if(e[i].v&&vis[e[i].to]!=T)
dfs(e[i].to,T);
}
void Gomory_Hu_Tree(int n){
rep(i,2,n)fa[i]=1;
rep(i,2,n){
s.insert(dinic(i,fa[i]));
static int T=0;T++;
dfs(i,T);
rep(j,i+1,n)
if(vis[j]==T&&fa[j]==fa[i])
fa[j]=i;
rep(j,2,cnt)e[j].v=e[j].c;
}
}
int main(){
//freopen("a.in","r",stdin);
int n,m;scanf("%d%d",&n,&m);
while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);insert(u,v,w);g[u][v]=g[v][u]=1;}
Gomory_Hu_Tree(n);
printf("%d\n",(int)s.size());
return 0;
}