「最小割树」学习笔记 & 「P4897 【模板】最小割树(Gomory-Hu Tree)」 题解
1.「P3627 [APIO2009] 抢掠计划(ATM)」题解2.「P3225 [HNOI2012] 矿场搭建」题解3.「P3214 [HNOI2011] 卡农」题解4.「旅游景点 Tourist Attractions」题解5.「ARC_172_A_Chocolate」题解6.「P1967 [NOIP 2013 提高组] 货车运输」题解7.「佳佳的 Fibonacci」题解8.「Fibonacci 前 n 项和」题解9.「P10668 BZOJ2720 [Violet 5] 列队春游」题解10.「P7394 「TOCO Round 1」History」题解11.「ABC375」题解12.「P6054 [RC-02] 开门大吉」题解
13.「最小割树」学习笔记 & 「P4897 【模板】最小割树(Gomory-Hu Tree)」 题解
最小割树
最小割树就是通过分治建出一棵树,树上两点的最小割就等于原图上的最小割,树上两点路径唯一,其最小割就等于路径上边权的最小值。
建树时,任意选择两点最为
之后对于这两部分再分别跑最小割,重复上述步骤,就能在理论(网络流的复杂度跑不满)
答案处理
建树
建树就是对于每一层分治将
因为原图两点的最小割就等于树上两点路径上边权的最小值,根据这点就可以有很多种处理方式了:
预处理,之后 ,总体查询复杂度- 树上倍增,查询复杂度也是
。 - 因为
是很小的,所以直接以每个点为根遍历一遍树预处理出答案也是可以的,复杂度 。 - ……
不建树
根据上面的式子,对于
根据这个式子,在分治的同时处理出答案即可,不需要把树建出来。
一些细节
- 每一次跑最小割前要将所有边恢复初始状态。
- 本题为无向图,要所以可以不用对于每一个边再建一条流量为
的反边了,建双向边即可。 - 注意分治时每层的
不同,根据需要保存本层的 。 - 因为数据有误,给定图的真实点数应该是
个,编号为 到 。
代码如下
使用的时不把树建出来的方法。
#include<bits/stdc++.h> #define ll long long #define mkp make_pair using namespace std; const int N=510,M=3010,inf=0x3f3f3f3f; #ifdef __linux__ #define gc getchar_unlocked #define pc putchar_unlocked #else #define gc _getchar_nolock #define pc _putchar_nolock #endif inline bool blank(const char x) {return !(x^32)||!(x^10)||!(x^13)||!(x^9);} template<typename Tp> inline void read(Tp &x) {x=0; register bool z=true; register char a=gc(); for(;!isdigit(a);a=gc()) if(a=='-') z=false; for(;isdigit(a);a=gc()) x=(x<<1)+(x<<3)+(a^48); x=(z?x:~x+1);} inline void read(double &x) {x=0.0; register bool z=true; register double y=0.1; register char a=gc(); for(;!isdigit(a);a=gc()) if(a=='-') z=false; for(;isdigit(a);a=gc()) x=x*10+(a^48); if(a!='.') return x=z?x:-x,void(); for(a=gc();isdigit(a);a=gc(),y/=10) x+=y*(a^48); x=(z?x:-x);} inline void read(char &x) {for(x=gc();blank(x)&&(x^-1);x=gc());} inline void read(char *x) {register char a=gc(); for(;blank(a)&&(a^-1);a=gc()); for(;!blank(a)&&(a^-1);a=gc()) *x++=a; *x=0;} inline void read(string &x) {x=""; register char a=gc(); for(;blank(a)&&(a^-1);a=gc()); for(;!blank(a)&&(a^-1);a=gc()) x+=a;} template<typename T,typename ...Tp> inline void read(T &x,Tp &...y) {read(x),read(y...);} template<typename Tp> inline void write(Tp x) {if(!x) return pc(48),void(); if(x<0) pc('-'),x=~x+1; register int len=0; register char tmp[64]; for(;x;x/=10) tmp[++len]=x%10+48; while(len) pc(tmp[len--]);} inline void write(const double x) {register int a=6; register double b=x,c=b; if(b<0) pc('-'),b=-b,c=-c; register double y=5*powl(10,-a-1); b+=y,c+=y; register int len=0; register char tmp[64]; if(b<1) pc(48); else for(;b>=1;b/=10) tmp[++len]=floor(b)-floor(b/10)*10+48; while(len) pc(tmp[len--]); pc('.'); for(c*=10;a;a--,c*=10) pc(floor(c)-floor(c/10)*10+48);} inline void write(const pair<int,double>x) {register int a=x.first; if(a<7) {register double b=x.second,c=b; if(b<0) pc('-'),b=-b,c=-c; register double y=5*powl(10,-a-1); b+=y,c+=y; register int len=0; register char tmp[64]; if(b<1) pc(48); else for(;b>=1;b/=10) tmp[++len]=floor(b)-floor(b/10)*10+48; while(len) pc(tmp[len--]); a&&(pc('.')); for(c*=10;a;a--,c*=10) pc(floor(c)-floor(c/10)*10+48);} else cout<<fixed<<setprecision(a)<<x.second;} inline void write(const char x) {pc(x);} inline void write(const bool x) {pc(x?49:48);} inline void write(char *x) {fputs(x,stdout);} inline void write(const char *x) {fputs(x,stdout);} inline void write(const string &x) {fputs(x.c_str(),stdout);} template<typename T,typename ...Tp> inline void write(T x,Tp ...y) {write(x),write(y...);} int n,m,s,t,cs[N],ct[N],dep[N],node[N],ans[N][N]; int tot=1,now[N],head[N],nxt[M],to[M],w[M]; inline void add(int x,int y,int z) { nxt[++tot]=head[x],to[head[x]=tot]=y,w[tot]=z; nxt[++tot]=head[y],to[head[y]=tot]=x,w[tot]=z; } inline bool bfs() { queue<int>q; memset(dep,0,sizeof(dep)); for(memcpy(now,head,sizeof(now)),q.push(s),dep[s]=1;!q.empty();) { int x=q.front(); q.pop(); for(int i=head[x],y;y=to[i];i=nxt[i]) if(w[i]&&!dep[y]) {dep[y]=dep[x]+1,q.push(y); if(y==t) return true;} } return false; } inline int dfs(int x,int sum) { if(x==t||!sum) return sum; int sur,res=0; for(int &i=now[x],y;y=to[i];i=nxt[i]) if(w[i]&&dep[y]==dep[x]+1) { if(!(sur=dfs(y,min(sum,w[i])))) {dep[y]=-1; continue;} w[i]-=sur,w[i^1]+=sur,res+=sur; if(!(sum-=sur)) break; } return res; } inline void build(int l,int r) { if(l>=r) return ; s=node[l],t=node[r]; int res=0,ns=0,nt=0; for(int i=2;i<tot;i+=2) w[i]=w[i^1]=w[i]+w[i^1]>>1; while(bfs()) res+=dfs(s,inf); ans[s][t]=ans[t][s]=res; for(int i=l,x;i<=r;i++) dep[x=node[i]]?cs[++ns]=x:ct[++nt]=x; for(int i=1;i<=ns;i++) node[l+i-1]=cs[i]; for(int i=1;i<=nt;i++) node[l+ns+i-1]=ct[i]; int os=s,ot=t; build(l,l+ns-1),build(l+ns,r); for(int i=1,j,x,y;i<=ns;i++) for(x=node[l+i-1],j=1;j<=nt;j++) y=node[l+ns+j-1],ans[x][y]=ans[y][x]=min({ans[x][os],ans[ot][y],res}); } signed main() { read(n,m),n++,memset(ans,0x3f,sizeof(ans)); for(int x,y,z;m--;) read(x,y,z),add(x+1,y+1,z); for(int i=1;i<=n;i++) node[i]=i; build(1,n),read(m); for(int x,y;m--;) read(x,y),write(ans[x+1][y+1],'\n'); }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2024-02-22 2024初三年后集训模拟测试4