ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-06-15 21:36:39  阅读:185  来源: 互联网

标签:tmp 原图 割树 int luogu Tree 最小 include define


题面传送门
看到一道题口胡出最小割树的做法了但是不会写。于是赶紧来学习一下。
首先最小割树的定义是:有这么一棵树,树上的边\((x,y)\)的权值为原图\(x,y\)之间的最小割的值。并且将这颗树的这条边断开划分出的两个点集是原图断开最小割的两个点集。
那么依据这个东西建树,先随便找到两个点,求出最小割,划分出点集,然后递归计算即可。
这个东西用\(dicnic\)实现,复杂度\(O(n^3m)\)
然后最小割树有一个奇妙的性质,就是树上两点间的最小边权是原图两点的最小割。
那么倍增查询即可。时间复杂度\(O(qlogn)\)
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 500
#define eps (1e-5)
#define mod (1<<31)
#define U unsigned int
using namespace std;
int n,m,d[N+5],nows[N+5],A[N+5],fa[N+5][10],F[N+5][10],S,T,lg[N+5],now,Q,x,y,z,B[N+5],Bh,C[N+5],Ch;
struct yyy{int to,w,z;}tmp;
struct ljb{
	int head,h[N+5];yyy f[N+5<<4];
	I void add(int x,int y,int z){
	f[head]=(yyy){y,z,h[x]};h[x]=head++;}
}s,G,Gs;queue<int> q;
I void get(int x,int y,int z){s.add(x,y,z);s.add(y,x,0);}
I int bfs(){
	while(!q.empty()) q.pop();memset(d,0x3f,sizeof(d));q.push(S);d[S]=0;nows[S]=s.h[S];
	while(!q.empty()){
		now=q.front();q.pop();for(int i=s.h[now];~i;i=tmp.z){
			tmp=s.f[i];if(!tmp.w||d[tmp.to]<1e9) continue;d[tmp.to]=d[now]+1;
			nows[tmp.to]=s.h[tmp.to];q.push(tmp.to);if(tmp.to==T) return 1; 
		}
	}
	return 0;
}
I int dfs(int x,int sum){
	if(x==T) return  sum;yyy tmp;int i,pus=0,k;for(i=nows[x];~i;i=tmp.z){
		tmp=s.f[i];nows[x]=i;if(!tmp.w||d[tmp.to]!=d[x]+1) continue;
		k=dfs(tmp.to,min(tmp.w,sum));if(!k) d[tmp.to]=1e9;
		sum-=k;pus+=k;s.f[i].w-=k;s.f[i^1].w+=k;if(!sum) break;
	}
	return pus;
}
I void build(int l,int r){
	if(l==r) return;re int i,Ans=0;S=A[l];T=A[r];s=G;while(bfs())Ans+=dfs(S,1e9);Gs.add(S,T,Ans);Gs.add(T,S,Ans); //printf("%d %d %d\n",Ans,S,T);
	Bh=Ch=0;for(i=l;i<=r;i++) (d[A[i]]<1e9?B[++Bh]:C[++Ch])=A[i];for(i=l;i<=l+Bh-1;i++) A[i]=B[i-l+1];
	for(i=l+Bh;i<=r;i++) A[i]=C[i-Bh-l+1];Ans=Bh;build(l,l+Ans-1);build(l+Ans,r);
}
I void Make(int x,int last){
	int i;d[x]=d[last]+1;yyy tmp;fa[x][0]=last;for(i=1;i<=lg[d[x]];i++) fa[x][i]=fa[fa[x][i-1]][i-1],F[x][i]=min(F[x][i-1],F[fa[x][i-1]][i-1]);
	for(i=s.h[x];~i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(F[tmp.to][0]=tmp.w,Make(tmp.to,x),0);
}
I void swap(int &x,int &y){x^=y^=x^=y;}
I int find(int x,int y){
	d[x]<d[y]&&(swap(x,y),0);int ans=1e9;while(d[x]^d[y])ans=min(ans,F[x][lg[d[x]-d[y]]]),x=fa[x][lg[d[x]-d[y]]];//printf("%d %d %d\n",ans,x,y);
	if(x==y) return ans;for(int i=lg[d[x]];~i;i--) fa[x][i]^fa[y][i]&&(ans=min(ans,min(F[x][i],F[y][i])),x=fa[x][i],y=fa[y][i]);return min(ans,min(F[x][0],F[y][0]));
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i,j;memset(s.h,-1,sizeof(s.h));memset(Gs.h,-1,sizeof(Gs.h));for(i=2;i<=n+1;i++)lg[i]=lg[i/2]+1;
	scanf("%d%d",&n,&m);for(i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&z),get(x,y,z),get(y,x,z);
	G=s;for(i=1;i<=n;i++) A[i]=i;build(0,n);s=Gs;memset(d,0,sizeof(d));Make(0,0);
	scanf("%d",&Q);while(Q--) scanf("%d%d",&x,&y),printf("%d\n",find(x,y));
}

标签:tmp,原图,割树,int,luogu,Tree,最小,include,define
来源: https://www.cnblogs.com/275307894a/p/14887212.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有