首页 > 其他分享 >最小割树

最小割树

时间:2023-09-05 16:48:10浏览次数:23  
标签:割树 int 最小 tot fa maxn ans dis

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

题意:求任意两个点的最小割。

首先任取两个点 \(s,t\) ,算出这两个点的最小割,然后将这两个点连上权值为 \(w\) 的边。求最小割的过程中,图被分为了两个联通块。在这两个联通块中递归执行上述过程,就能建成最小割树。

任意两个点的最小割,就是它们在树上的路径中边权的最小值。

下面的代码给出的是非递归建树的写法。

\(code:\)

#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int maxn=2e5+5;
int n,m,q,s,t,u,v,w,tot,flow,lg[maxn],vis[maxn],nxt[maxn],head[maxn],ver[maxn],edge[maxn],edge2[maxn],now[maxn],d[maxn],fa[maxn][20],dis[maxn][20],dep[maxn];
void add(int x,int y,int z){
    nxt[++tot]=head[x];head[x]=tot;
    ver[tot]=y;edge[tot]=edge2[tot]=z;
}
bool bfs(){
    queue <int> q;
    for(int i=1;i<=n;++i)
        d[i]=0;
    d[s]=1;now[s]=head[s];q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=nxt[i])
            if(!d[ver[i]]&&edge[i]){
                d[ver[i]]=d[x]+1;
                now[ver[i]]=head[ver[i]];
                if(ver[i]==t)
                    return 1;
                q.push(ver[i]);
            }
    }
    return 0;
}
int dfs(int x,int sum){
    if(x==t)
        return sum;
    int re=sum,k;
    for(int i=now[x];i&&re;i=nxt[i]){
        now[x]=i;
        if(d[ver[i]]==d[x]+1&&edge[i]){
            k=dfs(ver[i],min(re,edge[i]));
            if(!k)
                d[ver[i]]=0;
            edge[i]-=k;edge[i^1]+=k;re-=k;
        }
    }
    return sum-re;
}
void dfs2(int x){
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i])
        if(!vis[ver[i]]&&edge[i]>0)
            dfs2(ver[i]);
}
int dinic(int s,int t){
    int ans=0,sum=0;
    for(int i=1;i<=tot;++i)
        edge[i]=edge2[i];
    while(bfs())
        while(sum=dfs(s,1e9))
            ans+=sum;
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    tot=1;
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    for(int i=1;i<=n;++i)
        fa[i][0]=1;
    dis[1][0]=1e9;
    for(int i=2;i<=n;++i){
        s=i;t=fa[s][0];
        flow=dinic(s,t);
        dis[s][0]=flow;
        for(int j=1;j<=n;++j)
            vis[j]=0;
        dfs2(s);
        for(int j=i+1;j<=n;++j)
            if(vis[j]&&fa[j][0]==t)
                fa[j][0]=s;
    }
    dep[1]=1;
    for(int i=2;i<=n;++i){
        dep[i]=dep[fa[i][0]]+1;
        lg[i]=lg[i-1]+((1<<(lg[i-1]+1))==i);
    }
    for(int j=1;j<=19;++j)
        for(int i=2;i<=n;++i){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            dis[i][j]=min(dis[i][j-1],dis[fa[i][j-1]][j-1]);
        }
    scanf("%d",&q);
    for(int i=1;i<=q;++i){
        scanf("%d%d",&u,&v);
        if(dep[u]<dep[v])
            swap(u,v);
        int ans=1e9;
        while(dep[u]>dep[v]){
            ans=min(ans,dis[u][lg[dep[u]-dep[v]]]);
            u=fa[u][lg[dep[u]-dep[v]]];
        }
        if(u!=v){
            for(int i=19;i>=0;--i)
                if(fa[u][i]!=fa[v][i]){
                    ans=min(ans,min(dis[u][i],dis[v][i]));
                    u=fa[u][i],v=fa[v][i];
                }
            ans=min(ans,min(dis[u][0],dis[v][0]));
        }
        printf("%d\n",ans);
    }
    return 0;
}

P4123 [CQOI2016] 不同的最小割

仍然按照上面的方式建树,只需要统计树上边的种类即可。

标签:割树,int,最小,tot,fa,maxn,ans,dis
From: https://www.cnblogs.com/andyl/p/17680060.html

相关文章

  • linux教程:最小化安装的centos7如何安装图形化界面
    列出的组列表yumgrouplist安装yumgroupinstall-y"GNOMEDesktop"安装完成后,修改默认启动方式为图形化界面#设置成图形模式systemctlset-defaultgraphical.target如果要换回来#设置成命令模式systemctlset-defaultmulti-user.target然后重启系统即可......
  • 前端项目实战叁佰肆拾肆react-admin和material ui-设置布局最小高度
    constappLayout=(props:LayoutProps)=>{return(<Layoutsx={{'&.RaLayout-appFrame':{minHeight:'100%',height:'100%',margin:0,......
  • 最小年龄1-65的
    最小年龄1-65的验证规则TextInput::make('最小年龄')->type("number")->step(1)->rules([......
  • 2834. 找出美丽数组的最小和-360
    找出美丽数组的最小和给你两个正整数:n和target。如果数组nums满足下述条件,则称其为美丽数组。nums.length==n.nums由两两互不相同的正整数组成。在范围[0,n-1]内,不存在两个不同下标i和j,使得nums[i]+nums[j]==target。返回符合条件的美丽数组所可......
  • python中输出键最大、最小的项
     001、输出键最大的项a、>>>dict1={"c":30,"a":40,"b":80,"d":20,"e":60}>>>dict1{'c':30,'a':40,'b':80,'d':20,'e':60}>>&......
  • python中输出字典中值最大或最小的项
     001、输出值最大的项a、>>>dict1={"c":30,"a":40,"b":80,"d":60}##测试字典>>>dict1{'c':30,'a':40,'b':80,'d':60}>>>max_value=max(dict......
  • Qt将程序最小角化到系统托盘
      #include"test.h"#include"QPushButton"#include<QSystemTrayIcon>Test::Test(QWidget*parent):QWidget(parent){ui.setupUi(this);QPushButton*btn=newQPushButton(QString::fromLocal8Bit("最小化"),......
  • 剑指 Offer 40. 最小的k个数(简单)
    题目:classSolution{public:vector<int>getLeastNumbers(vector<int>&arr,intk){vector<int>result;sort(arr.begin(),arr.end());for(inti=0;i<k;i++){result.push_back(arr[i]);......
  • 用普里姆算法求最小生成树
    /*用普里姆算法求最小生成树*/#include<iostream>usingnamespacestd;/*邻接矩阵的类型定义*/#defineMAX10000000#defineMAX_VERTEX_NUM20typedefstruct{ charvexs[MAX_VERTEX_NUM];//用一维数组存储顶点信息 intedges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//用二维......
  • 文理分科(最大流最小割定理)
    传送门数据范围一眼网络流。考虑每个人文理只能选一个,考虑最小割。考虑源点\(S\)向\((i,j)\)连一条费用为\(art_{i,j}\)的边,\((i,j)\)向汇点\(T\)连一条费用为\(science_{i,j}\)的边。若割\(S\)与\((i,j)\)的边,则表示\((i,j)\)不选文,若割\((i,j_\)与\(T\)的边,则表示\((i,j)\)不......