[模板]最小割树(Gomory-Hu Tree)(luogu4897)

时间:2022-09-20 14:15:15

给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割

两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不连通

Input

第一行两个数\(n,m\)

接下来\(m\)行,每行3个数\(u,v,w\),表示有一条连接\(u\)与\(v\)的无向边,割断它的代价为\(w\)

接下来这一行有一个整数\(Q\),表示询问次数

接下来\(Q\)行,每行两个数\(u,v\),你需要求出\(u\)与\(v\)之间的最小割

Output

输出共\(Q\)行,每行一个整数对应询问的答案

Sample Input

4 5
1 2 2
2 3 2
4 2 3
4 3 1
1 3 1
3
1 4
2 4
2 3

Sample Output

3
4
4

Hint

\(n\leq 500,\quad m\leq 1500,\quad Q\leq 10^5,\quad 0\leq w\leq 10^4\)

题意:

求任意两点间的最小割(最大流)

题解:

本题要用到最小割树。

最小割树其实就是把所有的点分成多个部分然后分治,使只用跑很少次网络流就能解决两点之间的最小割。

举个例子:

这个图:

[模板]最小割树(Gomory-Hu Tree)(luogu4897)

开始先求1,4点间的最小割,易得为3。

跑完网络流之后的图是这样的。

[模板]最小割树(Gomory-Hu Tree)(luogu4897)

我们发现图变成了两部分,事实上,图肯定会变成两部分甚至更多,因为既然是一个割,就肯定会把两个点分到不同的区域。

然后易知两个区域之间的最小割至少为当前的最小割——3。

当前\(ans\)为

\[\begin{matrix}
0 & 3 & 3 & 3 \\
3 & 0 & inf & inf \\
3 & inf & 0 & inf \\
3 & inf & inf & 0
\end{matrix}
\]

然后我们把图复原

[模板]最小割树(Gomory-Hu Tree)(luogu4897)

在刚才划分的区域里继续划分

但有(1)区间只剩一个点了,所以不继续划分,取(2,3,4)中的2,3两点做最小割(其实随便哪两个不同的点都可以),易得最小割为4。

[模板]最小割树(Gomory-Hu Tree)(luogu4897)

然后易知两个区域之间的最小割至少为当前的最小割——4。

然后更新答案,记住,就算不在当前区间内的数也必须更新。

当前\(ans\)为

\[\begin{matrix}
0 & 3 & 3 & 3 \\
3 & 0 & 4 & inf \\
3 & 4 & 0 & 4 \\
3 & inf & 4 & 0
\end{matrix}
\]

继续复原,更新,然后得到最后的\(ans\):

\[\begin{matrix}
0 & 3 & 3 & 3 \\
3 & 0 & 4 & 4 \\
3 & 4 & 0 & 4 \\
3 & 4 & 4 & 0
\end{matrix}
\]

然后就可以根据询问输出了。

用这样的算法只用跑\(n\)遍网络流,因为每次必定分离两个点,乘上网络流复杂度\(O(n^2m)\)(其实跑不满)复杂度是\(O(n^3m)\)(也跑不满)。

至于为什么叫最小割树,大概是因为实际运算的时候每次都会把区间分为两部分,所以会分\(n-1\)次,然后每次会算出一个数(最小割),可以作为边权,然后就成了一棵树。

听说在这棵树上跑倍增找路径上的最小值也可以做这道题。

#include<bits/stdc++.h>
#define re register
using namespace std;
const int inf=1<<29,N=1010,M=20010;
int n,m,a[N];
int ans[N][N];
int head[N],nxt[M],bian[M],zhi[M],tot;
void init(){
tot=1;
memset(head,0,sizeof head);
}
inline void add(re int x,re int y,re int z){
tot++;bian[tot]=y;zhi[tot]=z;nxt[tot]=head[x];head[x]=tot;
tot++;bian[tot]=x;zhi[tot]=z;nxt[tot]=head[y];head[y]=tot;
}
inline void build(int m){
for(re int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
}
void rebuild(){
for(re int i=1;i<=tot;i+=2){
zhi[i]=zhi[i^1]=(zhi[i]+zhi[i^1])>>1;
}
}
int v[N],d[N];
void cut(int x){
v[x]=1;
for(int i=head[x];i;i=nxt[i]){
if(zhi[i]&&!v[bian[i]])cut(bian[i]);
}
}
queue<int>q;
bool bfs(int b,int e){
memset(d,0,sizeof(d));
while(!q.empty())q.pop();
q.push(b);d[b]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nxt[i]){
if(zhi[i] && !d[bian[i]]){
q.push(bian[i]);
d[bian[i]]=d[x]+1;
if(bian[i]==e)return 1;
}
}
}
return 0;
}
int dinic(int b,int e,int x,int flow){
if(x==e)return flow;
int rest=flow,k;
for(int i=head[x];i && rest;i=nxt[i]){
if(zhi[i] && d[bian[i]]==d[x]+1){
k=dinic(b,e,bian[i],min(rest,zhi[i]));
if(!k)d[bian[i]]=0;
zhi[i]-=k;
zhi[i^1]+=k;
rest-=k;
}
}
return flow-rest;
}
inline int maxflow(int b,int e){
int flow=0,maxflow=0;
while(bfs(b,e)){
while(flow=dinic(b,e,b,inf))maxflow+=flow;
}
return maxflow;
}
int b,e;
void solve(int l,int r){
if(l==r)return;
rebuild();
b=a[l],e=a[r];
re int mincut=maxflow(b,e);
memset(v,0,sizeof v);
cut(b);
for(re int i=1;i<=n;++i){
if(!v[i])continue;
for(re int j=1;j<=n;++j){
if(v[j])continue;
ans[i][j]=ans[j][i]=min(ans[i][j],mincut);
}
}
re int cnt=l-1;
static int ls[N];
for(re int i=l;i<=r;++i){
if(v[a[i]]){
ls[++cnt]=a[i];
}
}
re int fj=cnt;
for(re int i=l;i<=r;++i){
if(!v[a[i]]){
ls[++cnt]=a[i];
}
}
for(re int i=l;i<=r;++i)a[i]=ls[i];
solve(l,fj);
solve(fj+1,r);
}
int main()
{
int b,e,q;
memset(ans,0x3f,sizeof ans);
cin>>n>>m;
init();
build(m);
for(int i=1;i<=n;++i){
a[i]=i;
}
solve(1,n);
cin>>q;
while(q--){
scanf("%d%d",&b,&e);
if(ans[b][e]==0x3f3f3f3f)ans[b][e]=2147483647;
printf("%d\n",ans[b][e]);
}
}

[模板]最小割树(Gomory-Hu Tree)(luogu4897)的更多相关文章

  1. 最小割树Gomory–Hu tree

    fanhq666地址:http://fanhq666.blog.163.com/blog/static/8194342620113495335724/ wiki地址(证明):https://en.wi ...

  2. bzoj 4519&colon; &lbrack;Cqoi2016&rsqb;不同的最小割【最小割树Gomory–Hu tree】

    算法详见:http://www.cnblogs.com/lokiii/p/8191573.html 求出点两两之间的最小割之后,把他们扔到map/set里跑即可 可怕的是map和set跑的时间竟然完全 ...

  3. bzoj 2229&colon; &lbrack;Zjoi2011&rsqb;最小割【Gomory–Hu tree最小割树】

    这个算法详见http://www.cnblogs.com/lokiii/p/8191573.html 求出两两之间最小割之后暴力统计即可 #include<iostream> #inclu ...

  4. &lbrack;学习笔记&rsqb;最小割树(Gomory-Hu Tree)

    最小割树(\(\mathcal{Gomory-Hu Tree}\))简明指南 对于单源最短路径,我们有\(SPFA\)和\(Dijkstra\),对于多源最短路径,我们有\(Floyd\):对于两点间 ...

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

    传送门 Description 给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割 两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不 ...

  6. 洛谷&period;4897&period;&lbrack;模板&rsqb;最小割树&lpar;Dinic&rpar;

    题目链接 最小割树模板.具体见:https://www.cnblogs.com/SovietPower/p/9734013.html. ISAP不知为啥T成0分了.. Dinic: //1566ms ...

  7. 最小割树&lpar;Gomory-Hu Tree&rpar;

    当我们遇到这样的问题: 给定一个 \(n\) 个点 \(m\) 条边的无向连通图,多次询问两点之间的最小割 我们通常要用到最小割树. 博客 建树 分治.记录当前点集,然后随便找俩点当 \(s\) 和 ...

  8. 最小割树&lpar;Gomory-Hu Tree&rpar;求无向图最小割详解 附 BZOJ2229&comma;BZOJ4519题解

    最小割树(Gomory-Hu Tree) 前置知识 Gomory-Hu Tree是用来解决无向图最小割的问题的,所以我们需要了解无向图最小割的定义 和有向图类似,无向图上两点(x,y)的割定义为一个边 ...

  9. LoibreOJ 2042&period; 「CQOI2016」不同的最小割 最小割树 Gomory-Hu tree

    2042. 「CQOI2016」不同的最小割 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

随机推荐

  1. thinkphp 3&period;2 linux二级目录安装

    详解:http://document.thinkphp.cn/manual_3_2.html#url_rewrite 注意:linux系统对大小写敏感 服务器系统:linux (阿里云服务器) thi ...

  2. Webview组件和HTML的介绍

    Deviceone平台并不是基于html5的跨平台开发工具.我们开发一个app都是使用原生的组件,但是在某些场景下html5也是非常好的选择,比如复杂的图文混排(类似新闻),比如报表chart之类用h ...

  3. having——至少被订购过两回的订单

    此篇介绍having的用法 一.表:订单表,产品表 说明:订单表order ,包含prodectid 二.查询至少被订购过两回的订单 800x600 Normal 0 7.8 磅 0 2 false ...

  4. 暑假集训&lpar;2&rpar;第七弹 -----今年暑假不AC(hdu2037&rpar;

    J - 今年暑假不AC Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64 ...

  5. SNS团队Beta阶段第七次站立会议(2017&period;5&period;28)

    1.立会照片 2.每个人的工作 成员 今天已完成的工作 罗于婕 对界面各部分的图标进行完善.美化 龚晓婷 对于历史记录功能进一步完善 林仕庄 对于历史记录功能进一步完善 刘海兰 协调界面的整体美化 念 ...

  6. 使用genstring和NSLocalizedString实现App文本的本地化

    OS提供了简便的方法来实现本地化,其中用的最多的就是NSLocalizedString. 首先查看下NSLocalizedString是什么: #define NSLocalizedString(ke ...

  7. java无需解压zip压缩包直接读取包内的文件名(含中文)

    java自带了java.util.zip工具可以实现在不解压zip压缩包的情况下读取包内文件的文件名:(注:只能是ZIP格式的,rar我试了不行)代码如下: public static String ...

  8. pic&lowbar;scrapy&lowbar;python

    # _*_ coding:UTF-8 _*_ import requests,json,time,sys from contextlib import closing class get_photos ...

  9. ionic的actionsheet安卓样式不正常的坑及解决之道

    这是actionsheet该有的样子,可是android下变成了这样: 百度后,发现修改lonic.css,注释这段代码就可以了:

  10. 架构师修炼 III - 掌握设计原则

    关于软件的设计原则有很多,对于设计原则的掌握.理解.实践及升华是架构师的一项极为之必要的修炼. 记得在12年前第一次阅读<敏捷开发>时,五大基本设计原则就深深地植入到我的脑海中一直影响至今 ...