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]不同的最小割

  • 相关阅读:
    jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
    linux 查看服务器cpu 与内存配置
    arthas 使用总结
    selinux contexts 安全上下文的临时更改
    Android 8.1 Doze模式分析(五) Doze白名单及Debug方式
    Window 任意窗口置顶软件Window TopMost Control
    Android ApkToolPlus一个可视化的跨平台 apk 分析工具
    SVN Please execute the 'Cleanup' command.
    Android 如何在64位安卓系统中使用32位SO库
    Android cmd命令查看apk是32位还是64位?
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10130081.html
Copyright © 2011-2022 走看看