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\n",ans>=inf?-1:ans);  
    }
    return 0;
}                             

  

posted @ 2020-03-19 08:15  EM-LGH  阅读(130)  评论(0编辑  收藏  举报