[学习笔记]最小割树

用于求任意两个点的最小割(最大流)

最小割树建造方法:

类似于分治

在当前点集中选择任意两个点作为源点、汇点,跑最小割G

两个点之间连树边,边权为G

把当前点集中和源点联通的能到的放进一个集合里,与T联通的放进另一个集合里。然后分治下去

注意,每次跑最小割G是在全局跑。

n次最小割

建出树来之后,任意两点的最小割,就是两点树上路径的边权最小值。

证明不知。

扫描二维码关注公众号,回复: 4539337 查看本文章

https://blog.csdn.net/qq_33229466/article/details/53290996

可以证明最小是这个最小值,但是感觉不能证明能取到=。

代码:(找联通块的话,用dfs染色即可)

【模板】最小割树(Gomory-Hu Tree)

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=505;
const int M=15050;
const int inf=0x3f3f3f3f;
int n,m,s,t;
struct node{
    int nxt,to;
    int w;
}e[2*M],bian[2*M];
struct bbbb{
    int x,y,z;
}bb[M];
int hd[N],cnt=1;
void add(int x,int y,int z){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    e[cnt].w=z;
    hd[x]=cnt;
    
    e[++cnt].nxt=hd[y];
    e[cnt].to=x;
    e[cnt].w=z;
    hd[y]=cnt;
}
int pre[N],tot;
void add_c(int x,int y,int z){
    bian[++tot].nxt=pre[x];
    bian[tot].to=y;
    bian[tot].w=z;
    pre[x]=tot;
}
int d[N];
int dfs(int x,int flow){
    int res=flow;
    if(x==t) return flow;
    for(reg i=hd[x];i&&res;i=e[i].nxt){
        int y=e[i].to;
        if(e[i].w&&d[y]==d[x]+1){
            int k=dfs(y,min(e[i].w,res));
            if(!k) d[y]=0;
            res-=k;
            e[i].w-=k;
            e[i^1].w+=k;
        }
    }
    return flow-res;
}
int q[N],l,r;
bool bfs(){
    l=1,r=0;
    memset(d,0,sizeof d);
    d[s]=1;
    q[++r]=s;
    while(l<=r){
        int x=q[l++];
        //cout<<" bfs "<<x<<endl;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!d[y]&&e[i].w){
                d[y]=d[x]+1;
                q[++r]=y;
                if(y==t) return true;
            }
        }
    }
    return false;
}
int dinic(int x,int y){
    s=x,t=y;
    memset(hd,0,sizeof hd);
    cnt=1;
    for(reg i=1;i<=m;++i){
        add(bb[i].x,bb[i].y,bb[i].z);
    }
    int maxflow=0;
    int flow=0;
    while(bfs()){
        while(flow=dfs(s,inf)) maxflow+=flow;
    }
    return maxflow;
}
int ptr;
int mem[N],b[N],co[N];
bool in[N];
void fin(int x){
    co[x]=ptr;
    for(reg i=hd[x];i;i=e[i].nxt){
        if(e[i].w&&co[e[i].to]!=ptr) 
         fin(e[i].to);
    }
}
void divi(int l,int r){
    if(l==r) return;
    int ge=dinic(mem[l],mem[r]);
    add_c(mem[l],mem[r],ge);
    add_c(mem[r],mem[l],ge);
    ++ptr;
    fin(mem[l]);
    int pp=l-1,qq=r+1;
    for(reg i=l;i<=r;++i){
        if(co[mem[i]]==ptr) b[++pp]=mem[i];
        else b[--qq]=mem[i];
    }
    for(reg i=l;i<=r;++i){
        mem[i]=b[i];
    }
    divi(l,pp);divi(qq,r);
}
int fa[N][13],mi[N][13];
int dep[N];
void dfs2(int x,int deep){
    dep[x]=deep;
    for(reg i=pre[x];i;i=bian[i].nxt){
        int y=bian[i].to;
        if(y==fa[x][0]) continue;
        fa[y][0]=x;
        mi[y][0]=bian[i].w;
        dfs2(y,deep+1);
    }
}
int slo(int x,int y){
    int ans=inf;
    if(dep[x]<dep[y]) swap(x,y);
    for(reg i=12;i>=0;--i){
        if(dep[fa[x][i]]>=dep[y]) {
            ans=min(ans,mi[x][i]),x=fa[x][i];
        }
    }
    if(x==y) return ans;
    for(reg i=12;i>=0;--i){
        if(fa[x][i]!=fa[y][i]) {
            ans=min(ans,mi[x][i]);
            ans=min(ans,mi[y][i]);
            x=fa[x][i],y=fa[y][i];
        }
    }
    ans=min(ans,min(mi[x][0],mi[y][0]));
    return ans;
}
int main(){
    rd(n);rd(m);
    int x,y,z;
    for(reg i=1;i<=m;++i){
        rd(x);rd(y);rd(z);
        //add(x,y,z);
        bb[i].x=x,bb[i].y=y;bb[i].z=z;
    }
    for(reg i=1;i<=n;++i) mem[i]=i;
    divi(1,n);
    dfs2(1,1);
    for(reg j=1;j<=12;++j){
        for(reg i=1;i<=n;++i){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            mi[i][j]=min(mi[i][j-1],mi[fa[i][j-1]][j-1]);
        }
    }
    int T;
    rd(T);
    dep[0]=-1;
    while(T--){
        rd(x);rd(y);
        printf("%d\n",slo(x,y));
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/12/16 22:45:00
*/

还有两个模板题;[ZJOI2011]最小割 [CQOI2016]不同的最小割

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10130081.html