最小割树和网络流水题
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小割树和网络流水题相关的知识,希望对你有一定的参考价值。
最小割树和网络流水题
0.前置知识
最小割树,也叫 G o m o r y − H u T r e e Gomory-Hu\\ Tree Gomory−Hu Tree 。
用来解决无向图最小割的问题。
1.构造最小割树
分治+最小割构造
对于当前点集合区间 [ l , r ] [l,r] [l,r]。
- 从当前集合任意选择两个结点 s t , e d st,ed st,ed,求 ( s t , e d ) (st,ed) (st,ed)割
- 然后建立最小割树的边权 ( s t , e d , w ) (st,ed,w) (st,ed,w), w w w的 ( s t , e d ) (st,ed) (st,ed)的最小割。
- 然后根据最小割后的残余网络, d e p [ i ] ≠ 0 dep[i]\\ne 0 dep[i]=0的点加入一个集合,该集合是 s t st st可以访问的,而 d e p [ i ] = 0 dep[i]=0 dep[i]=0则是 s t st st访问不到的集合,是另一个集合。
- 然后递归解决这两个集合。
- 递归的终止条件是集合大小为 1 1 1,即 l = r l=r l=r。
- 因为是分治解决,跑 n n n次 d i n i c dinic dinic,时间复杂度: O ( n 3 m ) O(n^3m) O(n3m),但很难跑满。
void divi(int l,int r){
if(l==r) return;// 递归终止条件: 集合的大小为1.
st=t[l],ed=t[l+1]; //任意选择集合中的两个结点st,ed
ll w=dinic(); //求最小割w
add1(st,ed,w);// 最小割树建立边权edge(st,ed,w)
int c1=0,c2=0;//分治解决两个集合.
for(int i=l;i<=r;i++)
if(dep[t[i]]) t1[++c1]=t[i]; //集合1,st可以访问到的结点/
else t2[++c2]=t[i]; //st访问不到的结点.
for(int i=l;i<l+c1;i++) t[i]=t1[i-l+1];
for(int i=l+c1;i<=r;i++) t[i]=t2[i-l-c1+1];
divi(l,l+c1-1);//分治
divi(l+c1,r);
}
2.最小割树的性质
为了方便,令 λ ( u , v ) \\lambda(u,v) λ(u,v)为 u , v u,v u,v的最小割。
- 原图的 λ ( u , v ) = m i n { w e d g e ( i , j ) } , e d g e ( i , j ) \\lambda(u,v)=min\\{w_{edge}(i,j)\\},\\ edge(i,j) λ(u,v)=min{wedge(i,j)}, edge(i,j)是 u u u到 v v v路径上的边权。即答案就是树上 u , v u,v u,v两点路径的最小边权。
- 求树上两点路径最小边权,可以用倍增处理。
3.习题
P4897 【模板】最小割树
// Problem: P4897 【模板】最小割树(Gomory-Hu Tree)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4897
// Memory Limit: 125 MB
// Time Limit: 500 ms
// Date: 2021-07-21 20:40:49
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=505,M=6e3+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
//Dinic O(n^2m)
int n,m,st,ed;
int id(int x,int y){
return (x-1)*n+y;
}
struct edge{
int to,nt,w;
}e[M],g[M];
int h[N],cur[N],cnt=1,dep[N],cnt1,h1[N];
void add(int u,int v,int w){
e[++cnt]={v,h[u],w},h[u]=cnt;
e[++cnt]={u,h[v],0},h[v]=cnt;
}
void add1(int u,int v,int w){
g[++cnt1]={v,h1[u],w},h1[u]=cnt1;
g[++cnt1]={u,h1[v],w},h1[v]=cnt1;
}
int dfs(int u,int c){ //search for augment path
if(u==ed) return c;
int res=c;
for(int &i=cur[u];i;i=e[i].nt){
int v=e[i].to,w=e[i].w;
if(w&&dep[v]==dep[u]+1){
int now=dfs(v,min(res,w));
if(!now) dep[v]=1;
else e[i].w-=now,e[i^1].w+=now,res-=now;
}
if(!res) return c;
}return c-res;
}
bool bfs(){ //layer the graph
queue<int>q;q.push(st);mst(dep,0),dep[st]=1;
while(!q.empty()){
int u=q.front();q.pop();cur[u]=h[u];
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to,w=e[i].w;
if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
}
}return dep[ed];
}
ll dinic(){
for(int i=2;i<=cnt;i+=2) e[i].w=(e[i].w+e[i^1].w),e[i^1].w=0;
ll s=0;
while(bfs()) s+=dfs(st,inf);
return s;
}
int t[N],t1[N],t2[N];
void divi(int l,int r){
if(l==r) return;// 递归终止条件: 集合的大小为1.
st=t[l],ed=t[l+1]; //任意选择集合中的两个结点st,ed
ll w=dinic(); //求最小割w
add1(st,ed,w);// 最小割树建立边权edge(st,ed,w)
int c1=0,c2=0;//分治解决两个集合.
for(int i=l;i<=r;i++)
if(dep[t[i]]) t1[++c1]=t[i]; //集合1,st可以访问到的结点/
else t2[++c2]=t[i]; //st访问不到的结点.
for(int i=l;i<l+c1;i++) t[i]=t1[i-l+1];
for(int i=l+c1;i<=r;i++) t[i]=t2[i-l-c1+1];
divi(l,l+c1-1);//分治
divi(l+c1,r);
}
//倍增LCA
int f[N][21];
int mn[N][21];
void dfs(int u){
for(int i=h1[u];i;i=g[i].nt){
int v=g[i].to;
if(v!=f[u][0]){
f[v][0]=u;
mn[v][0]=g[i].w;
dep[v]=dep[u]+1;
dfs(v);
}
}
}
void init(){
for(int j=1;j<=10;j++)
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
mn[i][j]=min(mn[i][j-1],mn[f[i][j-1]][j-1]);
}
}
int query(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int delta=dep[u]-dep[v];
int ans=inf;
for(int i=0;i<=10;i++)
if(delta>>i&1){
ans=min(ans,mn[u][i]);
u=f[u][i];
}
if(u==v) return ans;
for(int i=10;~i;i--){
if(f[u][i]!=f[v][i]){
ans=min(ans,mn[u][i]);
ans=min(ans,mn[v][i]);
u=f[u][i],v=f[v][i];
网络战争 [KD-Tree+最小割树]