zoukankan      html  css  js  c++  java
  • [学习笔记]最小割树

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

    最小割树建造方法:

    类似于分治

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

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

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

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

    n次最小割

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

    证明不知。

    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
    ",slo(x,y));
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2018/12/16 22:45:00
    */

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

  • 相关阅读:
    2012 Multi-University #8
    2016"百度之星"
    Codeforces Round #352 (Div. 2)
    数位DP CF 55D Beautiful numbers
    数位DP GYM 100827 E Hill Number
    2012 Multi-University #9
    2012 Multi-University #10
    java生成指定范围的随机数
    MySql查询时间段的方法
    eclipse报错GC overhead limit exceed,卡顿
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10130081.html
Copyright © 2011-2022 走看看