最小割树(洛谷4897)

最小割树

求任意两点间的最小割

每次把当前点集中任意两点uv作为源汇跑最小割,连一条uv之间权值为最小割的边,之后按照分成的集合向下做

判断一条边是否为割边就直接判当前方向即可,注意可以走非当前集合的点

两点间最小割=新图中路径上的最小边权

证明:https://blog.csdn.net/axxgo7/article/details/54619560

code

要考虑0

#include 
#include 
#include 
#include 
#include 
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a=D[y])
    ans=min(ans,mn[x][i]),x=fa[x][i];
    
    fd(i,8,0)
    if (fa[x][i]!=fa[y][i])
    ans=min(ans,min(mn[x][i],mn[y][i])),x=fa[x][i],y=fa[y][i];
    
    if (x!=y) ans=min(ans,min(mn[x][0],mn[y][0]));
    return ans;
}

void Dfs(int Fa,int t)
{
    int i;
    
    fa[t][0]=Fa;
    D[t]=D[Fa]+1;
    fo(i,1,8)
    fa[t][i]=fa[fa[t][i-1]][i-1],mn[t][i]=min(mn[t][i-1],mn[fa[t][i-1]][i-1]);
    
    for (i=Ls[t]; i; i=aa[i][1])
    if (aa[i][0]!=Fa)
    {
        mn[aa[i][0]][0]=aa[i][2];
        Dfs(t,aa[i][0]);
    }
}

int main()
{
    #ifdef file
    freopen("luogu4897.in","r",stdin);
    #ifdef debug
    freopen("b.out","w",stdout);
    #endif
    #endif
    
    scanf("%d%d",&n,&m);len=1;++n;
    fo(i,1,m)
    {
        scanf("%d%d%d",&j,&k,&l);
        ++j;++k;
        
        New(j,k,l);
        New(k,j,l);
    }
    
    b[0]=n;
    fo(i,1,n)
    d[0][i]=i;
    
    work(0);
    Dfs(0,1);
    
    scanf("%d",&Q);
    for (;Q;--Q)
    {
        scanf("%d%d",&x,&y);++x;++y;
        printf("%d\n",js(x,y));
    }
}

你可能感兴趣的:(最小割树(洛谷4897))