最小割树(洛谷4897)

最小割树

求任意两点间的最小割

每次把当前点集中任意两点uv作为源汇跑最小割,连一条uv之间权值为最小割的边,之后按照分成的集合向下做

判断一条边是否为割边就直接判当前方向即可,注意可以走非当前集合的点

两点间最小割=新图中路径上的最小边权

证明:https://blog.csdn.net/axxgo7/article/details/54619560

code

要考虑0

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define inf 2133333333
//#define file
#define debug
using namespace std;

int aa[1111][3];
int Ls[512];
int a[3102][3];
int A[3102];
int ls[512];
int cur[512];
int f[512];
int g[512];
int d[512][512];
int b[512];
int bz[512];
int d2[512];
int fa[512][9];
int mn[512][9];
int D[512];
bool Bz[512];
int Q,n,m,i,j,k,l,len,st,ed,Len,h2,t2,x,y;

void New(int x,int y,int z)
{
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
	a[len][2]=A[len]=z;
}

void NEW(int x,int y,int z)
{
	++Len;
	aa[Len][0]=y;
	aa[Len][1]=Ls[x];
	Ls[x]=Len;
	aa[Len][2]=z;
}

int dfs(int t,int flow)
{
	int i,use=0;
	
	if (t==ed)
	return flow;
	
	for (i=cur[t]; i; i=a[i][1])
	{
		cur[t]=i;
		
		if (f[t]==f[a[i][0]]+1 && a[i][2])
		{
			int w=dfs(a[i][0],min(flow-use,a[i][2]));
			
			a[i][2]-=w;
			a[i^1][2]+=w;
			use+=w;
			
			if (use==flow)
			return use;
		}
	}
	cur[t]=ls[t];
	
	--g[f[t]];
	if (!g[f[t]])
	{
		f[st]=n+1;
		return use;
	}
	++f[t];++g[f[t]];
	
	return use;
}

void work(int t)
{
	int Ans=0;
	
	if (b[t]<=1)
	return;
	
	memset(f,0,sizeof(f));
	memset(g,0,sizeof(g));
	fo(i,1,len) a[i][2]=A[i];
	
	g[0]=n;
	st=d[t][1];
	ed=d[t][2];
	
	while (f[st]<=n)
	Ans+=dfs(st,inf);
	
	NEW(st,ed,Ans);
	NEW(ed,st,Ans);
	
	b[t+1]=1;
	d[t+1][1]=st;
	bz[st]=t+1;
	
	memset(Bz,0,sizeof(Bz));Bz[st]=1;
	h2=0;t2=1;
	d2[1]=st;
	while (h2<t2)
	{
		for (i=ls[d2[++h2]]; i; i=a[i][1])
		if (a[i][2] && !Bz[a[i][0]])
		{
			Bz[a[i][0]]=1;
			d2[++t2]=a[i][0];
			
			if (bz[a[i][0]]==t)
			{
				bz[a[i][0]]=t+1;
				d[t+1][++b[t+1]]=a[i][0];
			}
		}
	}
	work(t+1);
	
	b[t+1]=0;
	fo(i,1,b[t])
	if (bz[d[t][i]]==t+1)
	bz[d[t][i]]=t;
	else
	if (bz[d[t][i]]==t)
	{
		d[t+1][++b[t+1]]=d[t][i];
		bz[d[t][i]]=t+1;
	}
	
	work(t+1);
	fo(i,1,b[t])
	if (bz[d[t][i]]==t+1)
	bz[d[t][i]]=t;
}

void swap(int &x,int &y)
{
	int z=x;
	x=y;
	y=z;
}

int js(int x,int y)
{
	int i,ans=inf;
	
	if (D[x]<D[y])
	swap(x,y);
	
	fd(i,8,0)
	if (D[fa[x][i]]>=D[y])
	ans=min(ans,mn[x][i]),x=fa[x][i];
	
	fd(i,8,0)
	if (fa[x][i]!=fa[y][i])
	ans=min(ans,min(mn[x][i],mn[y][i])),x=fa[x][i],y=fa[y][i];
	
	if (x!=y) ans=min(ans,min(mn[x][0],mn[y][0]));
	return ans;
}

void Dfs(int Fa,int t)
{
	int i;
	
	fa[t][0]=Fa;
	D[t]=D[Fa]+1;
	fo(i,1,8)
	fa[t][i]=fa[fa[t][i-1]][i-1],mn[t][i]=min(mn[t][i-1],mn[fa[t][i-1]][i-1]);
	
	for (i=Ls[t]; i; i=aa[i][1])
	if (aa[i][0]!=Fa)
	{
		mn[aa[i][0]][0]=aa[i][2];
		Dfs(t,aa[i][0]);
	}
}

int main()
{
	#ifdef file
	freopen("luogu4897.in","r",stdin);
	#ifdef debug
	freopen("b.out","w",stdout);
	#endif
	#endif
	
	scanf("%d%d",&n,&m);len=1;++n;
	fo(i,1,m)
	{
		scanf("%d%d%d",&j,&k,&l);
		++j;++k;
		
		New(j,k,l);
		New(k,j,l);
	}
	
	b[0]=n;
	fo(i,1,n)
	d[0][i]=i;
	
	work(0);
	Dfs(0,1);
	
	scanf("%d",&Q);
	for (;Q;--Q)
	{
		scanf("%d%d",&x,&y);++x;++y;
		printf("%d\n",js(x,y));
	}
}
posted @ 2019-12-23 23:45  gmh77  阅读(159)  评论(0编辑  收藏  举报