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


    吸氧才能过,写一个分治就行. 

    这里讲一下构造方法:考虑对点集 $U$ 求最小割树.  

    随便选取两个点 $u,v$ 然后跑一个 $u$ 到 $v$ 的最小割.  

    然后有两条性质: 

    • 对于 $U$ 中的每个点,一定被划分到了 $u$ 集合或 $v$ 集合(废话)  
    • 对于 $u$ 集合点到 $v$ 集合点的最小割一定小于等于 $u$ 到 $v$ 的最小割(最坏情况也可以取到 $u$ 到 $v$ 的最小割)     

    然后这么递归,一共跑 $n-1$ 次最大流,查询的时候查询树上路径最小边权就行了.  

    code:     

    #include <cstdio>  
    #include <cstring> 
    #include <string>    
    #include <queue>    
    #include <vector>    
    #define N 503    
    #define ll long long      
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std; 
    namespace net
    {
        #define inf 1000000000 
        struct Edge 
        {
            int u,v,c;
            Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){} 
        };   
        queue<int>q; 
        vector<Edge>edges;  
        vector<int>G[N];       
        int vv[N],vis[N],d[N],col[N],s,t;       
        void add(int u,int v,int c) 
        {
            edges.push_back(Edge(u,v,c));
            edges.push_back(Edge(v,u,0));  
            int o=edges.size();  
            G[u].push_back(o-2);
            G[v].push_back(o-1);      
        }    
        int dfs(int x,int cur) 
        { 
            if(x==t) 
                return cur;  
            int an=0,flow=0;
            for(int i=vv[x];i<G[x].size();++i,++vv[x])       
            {
                Edge e=edges[G[x][i]];  
                if(e.c>0&&d[e.v]==d[x]+1) 
                {     
                    an=dfs(e.v,min(cur,e.c));   
                    if(an) 
                    {
                        cur-=an;
                        flow+=an;            
                        edges[G[x][i]].c-=an;
                        edges[G[x][i]^1].c+=an;    
                        if(!cur) 
                            break;   
                    }
                }
            }
            return flow; 
        }
        int bfs()  
        {    
            memset(vis,0,sizeof(vis));
            d[s]=0;
            vis[s]=1;
            q.push(s);
            while(!q.empty()) 
            {
                int u=q.front();
                q.pop(); 
                for(int i=0;i<G[u].size();++i) 
                {
                    if(edges[G[u][i]].c>0) 
                    {
                        int v=edges[G[u][i]].v;  
                        if(!vis[v]) 
                        {
                            vis[v]=1;
                            d[v]=d[u]+1;  
                            q.push(v);  
                        }
                    }
                }
            }
            return vis[t]; 
        }   
        int maxflow() 
        {
            int re=0;
            while(bfs())   
            { 
                memset(vv,0,sizeof(vv));           
                re+=dfs(s,inf);  
            }
            return re;
        }   
        void emp() 
        { 
            memset(vv,0,sizeof(vv));  
            memset(vis,0,sizeof(vis)); 
            memset(d,0,sizeof(d));           
            for(int i=0;i<edges.size();i+=2) 
            {
                edges[i].c+=edges[i^1].c;       
                edges[i^1].c=0;  
            }
        }   
        void mark(int x,int co) 
        {   
            if(col[x]==co)  
                return;    
            col[x]=co;   
            for(int i=0;i<G[x].size();++i) 
            {
                Edge e=edges[G[x][i]];   
                if(e.c>0) 
                    mark(e.v,co);    
            }
        }
    };        
    int n,m,edges,id,dep[N];  
    int minn[15][N],fa[15][N];         
    int tmp1[N],tmp2[N],a[N],hd[N],to[N<<1],nex[N<<1],val[N<<1];   
    void add(int u,int v,int c) 
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;  
    }               
    void solve(int l,int r) 
    {    
        if(l>=r)  
            return;      
        ++id;    
        net::emp();  
        net::s=a[l];   
        net::t=a[l+1];          
        int cur=net::maxflow();         
        add(a[l],a[l+1],cur);   
        add(a[l+1],a[l],cur);                    
        net::mark(a[l],id);         
        int t1=0,t2=0; 
        for(int i=l;i<=r;++i) 
            if(net::col[a[i]]==id)     
                tmp1[++t1]=a[i];                     
            else  
                tmp2[++t2]=a[i];    
        int L=l,R=r;   
        for(int i=1;i<=t1;++i)    
            a[L++]=tmp1[i];   
        for(int i=1;i<=t2;++i)   
            a[L++]=tmp2[i];     
        solve(l,l+t1-1);    
        solve(r-t2+1,r);         
    }      
    void dfs(int x,int ff) 
    {     
        dep[x]=dep[ff]+1; 
        for(int i=1;i<15;++i) 
        {
            fa[i][x]=fa[i-1][fa[i-1][x]];   
            minn[i][x]=min(minn[i-1][x],minn[i-1][fa[i-1][x]]);    
        }            
        for(int i=hd[x];i;i=nex[i]) 
        {
            int y=to[i];   
            if(y==ff)  
                continue;      
            fa[0][y]=x;  
            minn[0][y]=val[i];   
            dfs(y,x); 
        }
    }
    int query(int x,int y) 
    {
        if(dep[x]>dep[y]) 
            swap(x,y);   
        int re=inf;    
        if(dep[x]!=dep[y]) 
        { 
            for(int i=14;i>=0;--i)    
                if(dep[fa[i][y]]>=dep[x])    
                    re=min(re,minn[i][y]),y=fa[i][y];   
        }     
        if(x==y)  
            return re;   
        for(int i=14;i>=0;--i) 
        {
            if(fa[i][x]!=fa[i][y])   
            {
                re=min(re,minn[i][x]);  
                re=min(re,minn[i][y]);  
                x=fa[i][x];  
                y=fa[i][y];  
            }
        } 
        re=min(re,minn[0][x]); 
        re=min(re,minn[0][y]);   
        return re;   
    }    
    int main() 
    {
        // setIO("input");   
        scanf("%d%d",&n,&m);                     
        for(int i=1;i<=m;++i) 
        {
            int u,v,w;     
            scanf("%d%d%d",&u,&v,&w);     
            net::add(u,v,w); 
            net::add(v,u,w);                  
        }                           
        for(int i=1;i<=n;++i)  
            a[i]=i;   
        memset(minn,0x3f,sizeof(minn));    
        solve(1,n),dfs(1,0);         
        int Q; 
        scanf("%d",&Q); 
        for(int i=1;i<=Q;++i) 
        {
            int x,y,ans;  
            scanf("%d%d",&x,&y);   
            ans=query(x,y);   
            printf("%d
    ",ans>=inf?-1:ans);  
        }
        return 0;
    }                             
    

      

  • 相关阅读:
    C# 多线程Thread.IsBackground=True的作用
    JS 判断用户设备 移动端或桌面端
    VSCode 代码格式化 快捷键
    PHP 根据 IP 获取定位数据
    C# 将文本写入到文件
    C# 读取文件内容
    PHP 美化输出数组
    VSCode 设置 Tab 空格
    custom post types 404 Page Error
    [已解决] wordpress 修改 permalink 后 页面 404 问题
  • 原文地址:https://www.cnblogs.com/guangheli/p/12521891.html
Copyright © 2020-2023  润新知