最小割树

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int maxn=1005;
const ll inf=20000000000005ll;

struct edge //树上的边 
{
	int u,v,next;
	ll w;
}e[maxn*10];

int f[maxn],cnt=-1,n,m;
int fa[maxn][20],deep[maxn],mn[maxn][20];//树上的数据  mn为快速lca中的边的最小值(也就是最小割) 
//树上的边便是两个相邻点的最小割,两个点的lca经过的边的最小值就是两个点的最小割 

void add(int u,int v,ll F){
	e[++cnt]=(edge){u,v,f[u],F};f[u]=cnt;
	e[++cnt]=(edge){v,u,f[v],F};f[v]=cnt;
}

namespace Get_Tree// 用网络流跑最小割建树 
{
	struct edge
	{
		int u,v,next;
		ll f,c;
	}e[maxn*10];

	int tot,f[maxn],s,t,cur[maxn],d[maxn],cnt=-1,q[maxn*10],col[maxn],col_bucket[maxn],node[maxn];
	
	void add(int u,int v,ll F){
		e[++cnt]=(edge){u,v,f[u],F,0};f[u]=cnt;
		e[++cnt]=(edge){v,u,f[v],0,0};f[v]=cnt;
	}
	
	bool bfs(){
		int frond=0,root=0;
		memset(d,0,sizeof(d));
		q[root++]=s;
		d[s]=1;
		while(root!=frond)
		{
			int i=q[frond++];
			for(int k=f[i];k!=-1;k=e[k].next)
			{
				int j=e[k].v;
				if(d[j]||e[k].f==e[k].c) continue;
				d[j]=d[i]+1;
				q[root++]=j;
			}
		}
		return d[t];
	}

	ll dfs(int i,ll a){
		if(i==t||a==0) return a;
		ll F,flow=0;
		for(int &k=cur[i];k!=-1;k=e[k].next)
		{
			int j=e[k].v;
			if(d[j]==d[i]+1&&(F=dfs(j,min(a,(ll)e[k].f-e[k].c))))
			{
				a-=F;
				flow+=F;
				e[k].c+=F;
				e[k^1].c-=F;
				if(!a) break;
			}
		}
		return flow;
	}

	ll dinic(int x,int y){
		ll flow=0;
		s=x;t=y;
		for(int i=0;i<=cnt;i++) e[i].c=0;
		while(bfs())
		{
			memcpy(cur,f,sizeof(cur));
			flow+=dfs(s,inf);
		}
		return flow;
	}	

	void get_color(int now,int color)
	{
   	    col[now]=color;
        for(int i=f[now];i!=-1;i=e[i].next)
   	         if(e[i].f>e[i].c&&col[e[i].v]!=color)
                get_color(e[i].v,color);
	}

	void build(int l,int r)
	{
 		if(l==r) return;
  		int x=node[l],y=node[l+1];
  		int cut=dinic(x,y);
  		get_color(x,++tot);
   		int L=l,R=r;
   		for(int i=l;i<=r;i++)
        	if(col[node[i]]==tot) col_bucket[L++]=node[i];
        	else col_bucket[R--]=node[i];
    	for(int i=l;i<=r;i++) node[i]=col_bucket[i];
    	::add(x,y,cut);
    	build(l,L-1);
    	build(R+1,r);
	}
}

void dfs(int now) //处理树上的数据 
{
    for(int i=1;i<=9;i++)
    {
        fa[now][i]=fa[fa[now][i-1]][i-1];
        mn[now][i]=min(mn[now][i-1],mn[fa[now][i-1]][i-1]);
    }
    for(int i=f[now];i!=-1;i=e[i].next)
    {
        if(e[i].v==fa[now][0]) continue;
        deep[e[i].v]=deep[now]+1,fa[e[i].v][0]=now,mn[e[i].v][0]=e[i].w;
        dfs(e[i].v);
    }
}

int getcut(int x,int y) // x和y之间的最小割 
{
    int re=INT_MAX;
    if(deep[x]<deep[y]) swap(x,y);
    for(int i=9;i>=0;i--) if(deep[fa[x][i]]>=deep[y]) re=min(re,mn[x][i]),x=fa[x][i];
    if(x==y) return re;
    for(int i=9;i>=0;i--) if(fa[x][i]!=fa[y][i]) re=min(re,min(mn[x][i],mn[y][i])),x=fa[x][i],y=fa[y][i];
    return min(re,min(mn[x][0],mn[y][0]));
}

int main()
{
	scanf("%d%d",&n,&m); 
	for(int i=1;i<=n;i++) f[i]=-1,Get_Tree::f[i]=-1;
	int x,y,w;
	for(int i=1;i<=n;i++) Get_Tree::node[i]=i;
	for(int j=1;j<=m;j++)
	{
		scanf("%d%d%d",&x,&y,&w);
		Get_Tree::add(y,x,w);
		Get_Tree::add(x,y,w);
	}
	Get_Tree::build(1,n); 
	deep[1]=1;
	dfs(1);
	int Q;
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++) 
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",getcut(x,y));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值