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

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

Input

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

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

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

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

Output

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

Sample Input

  1. 4 5
  2. 1 2 2
  3. 2 3 2
  4. 4 2 3
  5. 4 3 1
  6. 1 3 1
  7. 3
  8. 1 4
  9. 2 4
  10. 2 3

Sample Output

  1. 3
  2. 4
  3. 4

Hint

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

题意:

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

题解:

本题要用到最小割树。

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

举个例子:

这个图:



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

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



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

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

当前\(ans\)为

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

然后我们把图复原



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

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



然后易知两个区域之间的最小割至少为当前的最小割——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\)次,然后每次会算出一个数(最小割),可以作为边权,然后就成了一棵树。

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

  1. #include<bits/stdc++.h>
  2. #define re register
  3. using namespace std;
  4. const int inf=1<<29,N=1010,M=20010;
  5. int n,m,a[N];
  6. int ans[N][N];
  7. int head[N],nxt[M],bian[M],zhi[M],tot;
  8. void init(){
  9. tot=1;
  10. memset(head,0,sizeof head);
  11. }
  12. inline void add(re int x,re int y,re int z){
  13. tot++;bian[tot]=y;zhi[tot]=z;nxt[tot]=head[x];head[x]=tot;
  14. tot++;bian[tot]=x;zhi[tot]=z;nxt[tot]=head[y];head[y]=tot;
  15. }
  16. inline void build(int m){
  17. for(re int i=1;i<=m;i++){
  18. int x,y,z;
  19. scanf("%d%d%d",&x,&y,&z);
  20. add(x,y,z);
  21. }
  22. }
  23. void rebuild(){
  24. for(re int i=1;i<=tot;i+=2){
  25. zhi[i]=zhi[i^1]=(zhi[i]+zhi[i^1])>>1;
  26. }
  27. }
  28. int v[N],d[N];
  29. void cut(int x){
  30. v[x]=1;
  31. for(int i=head[x];i;i=nxt[i]){
  32. if(zhi[i]&&!v[bian[i]])cut(bian[i]);
  33. }
  34. }
  35. queue<int>q;
  36. bool bfs(int b,int e){
  37. memset(d,0,sizeof(d));
  38. while(!q.empty())q.pop();
  39. q.push(b);d[b]=1;
  40. while(!q.empty()){
  41. int x=q.front();q.pop();
  42. for(int i=head[x];i;i=nxt[i]){
  43. if(zhi[i] && !d[bian[i]]){
  44. q.push(bian[i]);
  45. d[bian[i]]=d[x]+1;
  46. if(bian[i]==e)return 1;
  47. }
  48. }
  49. }
  50. return 0;
  51. }
  52. int dinic(int b,int e,int x,int flow){
  53. if(x==e)return flow;
  54. int rest=flow,k;
  55. for(int i=head[x];i && rest;i=nxt[i]){
  56. if(zhi[i] && d[bian[i]]==d[x]+1){
  57. k=dinic(b,e,bian[i],min(rest,zhi[i]));
  58. if(!k)d[bian[i]]=0;
  59. zhi[i]-=k;
  60. zhi[i^1]+=k;
  61. rest-=k;
  62. }
  63. }
  64. return flow-rest;
  65. }
  66. inline int maxflow(int b,int e){
  67. int flow=0,maxflow=0;
  68. while(bfs(b,e)){
  69. while(flow=dinic(b,e,b,inf))maxflow+=flow;
  70. }
  71. return maxflow;
  72. }
  73. int b,e;
  74. void solve(int l,int r){
  75. if(l==r)return;
  76. rebuild();
  77. b=a[l],e=a[r];
  78. re int mincut=maxflow(b,e);
  79. memset(v,0,sizeof v);
  80. cut(b);
  81. for(re int i=1;i<=n;++i){
  82. if(!v[i])continue;
  83. for(re int j=1;j<=n;++j){
  84. if(v[j])continue;
  85. ans[i][j]=ans[j][i]=min(ans[i][j],mincut);
  86. }
  87. }
  88. re int cnt=l-1;
  89. static int ls[N];
  90. for(re int i=l;i<=r;++i){
  91. if(v[a[i]]){
  92. ls[++cnt]=a[i];
  93. }
  94. }
  95. re int fj=cnt;
  96. for(re int i=l;i<=r;++i){
  97. if(!v[a[i]]){
  98. ls[++cnt]=a[i];
  99. }
  100. }
  101. for(re int i=l;i<=r;++i)a[i]=ls[i];
  102. solve(l,fj);
  103. solve(fj+1,r);
  104. }
  105. int main()
  106. {
  107. int b,e,q;
  108. memset(ans,0x3f,sizeof ans);
  109. cin>>n>>m;
  110. init();
  111. build(m);
  112. for(int i=1;i<=n;++i){
  113. a[i]=i;
  114. }
  115. solve(1,n);
  116. cin>>q;
  117. while(q--){
  118. scanf("%d%d",&b,&e);
  119. if(ans[b][e]==0x3f3f3f3f)ans[b][e]=2147483647;
  120. printf("%d\n",ans[b][e]);
  121. }
  122. }

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

  1. 最小割树Gomory–Hu tree

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

  2. bzoj 4519: [Cqoi2016]不同的最小割【最小割树Gomory–Hu tree】

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

  3. bzoj 2229: [Zjoi2011]最小割【Gomory–Hu tree最小割树】

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

  4. [学习笔记]最小割树(Gomory-Hu Tree)

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

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

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

  6. 洛谷.4897.[模板]最小割树(Dinic)

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

  7. 最小割树(Gomory-Hu Tree)

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

  8. 最小割树(Gomory-Hu Tree)求无向图最小割详解 附 BZOJ2229,BZOJ4519题解

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

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

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

随机推荐

  1. 【搜索】 Prime Path

    #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include& ...

  2. Socket 学习笔记 01 常用函数

    常用方法 创建套接字: socket()    绑定本机端口: bind()    建立连接: connect(),accept()    侦听端口: listen()    数据传输: send() ...

  3. NOIP水题测试(2017082401)

    哈,水题测试又来了! 上次的水题简单吧! 答案是以单题形式发布的(旅行家的预算随后发布). 下面来看今天的题,还是水题. 时间限制:5小时 题目一:看上去就很水 题目二:比上面一题还水 题目三:数的划 ...

  4. 数据分析计算xgboost模块

    一.安装xgboost方法 摘要:之前为了安装xgboost,少不了进入各种坑,但最终安装成功了!首先, 准备的工作:,下载mingw64,链接https://pan.baidu.com/s/1i5C ...

  5. my.ini优化mysql数据库性能的十个参数(推荐)

    (1).max_connections:允许的同时客户的数量.增加该值增加 mysqld 要求的文件描述符的数量.这个数字应该增加,否则,你将经常看到 too many connections 错误. ...

  6. TCP/IP协议(6):传输层之UDP

    一. UDP用户数据报协议,它是一个无连接的,面向数据报的协议,它不提供可靠性但传输速度比TCP要快. UDP数据报中的“UDP长度”为两个字节,所以我们要发送的UDP数据最多支持65507大约68K ...

  7. s5-2 Cpu调度算法

    调度程序采用什么算法选择一个进程(作业)? 如何评价调度算法的性能? 调度准则 CPU利用率 – 使CPU尽可能的忙碌 吞吐量 – 单位时间内运行完的进程数 周转时间 – 进程从提交到运行结束的全部时 ...

  8. 根据方法名获取方法Body Content

    利用 MethodBody类的GetILAsByteArray方法可以获取到返回字节数组的MSIL的body.然后再去解析此字节数组, 可以得到MSIL,然后你再去解析MSIL,你就可以得到你想到so ...

  9. linux cp操作,每天学习一点

    指令名称:cp(copy)功能介绍:将一个文件复制至另一个文件,或将数个文件复制至另一目录. 语法格式: cp [options] source dest  cp [options] source.. ...

  10. Windows 下 Quartus 检测不到 USB-Blaster 终极解决办法

    转自https://blog.csdn.net/acang301/article/details/50471067?locationNum=12 一.Windows无法正常驱动USB-Blaster ...