最小割树学习笔记

分治选两个点跑最大流再分即可

#include<cstdio>

#define maxn 555
#define maxm 2222
#define INF 1000000000

inline int read(){
	int r=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')r=(r<<1)+(r<<3)+(c^48),c=getchar();
	return r*f;
}

inline int min(int a,int b){
	return a<b?a:b;
}

inline void swap(int &a,int &b){
	int c=a;
	a=b;
	b=c;
}

int n,m,q;

struct Flow{

	struct E{
		int v,c,nxt;
		E() {}
		E(int v,int c,int nxt):v(v),c(c),nxt(nxt) {}
	}e[maxm*4];

	int s,t,hd,tl,s_e,head[maxn],cur[maxn],lev[maxn],q[maxn];

	inline void a_e(int u,int v,int c){
		e[++s_e]=E(v,c,head[u]);
		head[u]=s_e;
	}

	inline void add(int u,int v,int c){
		a_e(u,v,c);
		a_e(v,u,0);
	}

	inline void init(int S,int T){
		s_e=1;
		s=S,t=T;
		for(int i=1;i<=n;i++)head[i]=0;
	}

	inline bool BFS(){
		hd=tl=0;
		for(int i=1;i<=n;i++)
			lev[i]=0,cur[i]=head[i];
		lev[s]=1;
		q[++tl]=s;
		while(hd^tl){
			int u=q[++hd];
			for(int i=head[u];i;i=e[i].nxt){
				int v=e[i].v,c=e[i].c;
				if(!c||lev[v])continue;
				lev[v]=lev[u]+1;
				q[++tl]=v;
				if(v==t)return true;
			}
		}
		return false;
	}

	int dfs(int u,int f){
		int d=0,used=0;
		if(!(u^t))return f;
		for(int &i=cur[u];i;i=e[i].nxt){
			int v=e[i].v;
			if(!e[i].c||(lev[v]^(lev[u]+1)))continue;
			d=dfs(v,min(f-used,e[i].c));
			if(!d)continue;
			used+=d;
			e[i].c-=d;
			e[i^1].c+=d;
			if(used==f)break;
		}
		if(!used)lev[u]=0;
		return used;
	}

	inline int dinic(){
		int max_flow=0,d=0;
		while(BFS())
			while((d=dfs(s,INF)))
				max_flow+=d;
		return max_flow;
	}

}flow;

struct Tree{

	struct E{
		int v,w,nxt;
		E() {}
		E(int v,int w,int nxt):v(v),w(w),nxt(nxt) {}
	}e[maxm*2];

	int s_e,head[maxn],dot[maxn],be[maxn],uu[maxm],vv[maxm],cc[maxm];

	bool vis[maxn];

	inline void a_e(int u,int v,int w){
		e[++s_e]=E(v,w,head[u]);
		head[u]=s_e;
	}

	inline void init(){
		for(int i=1;i<=n;i++)
			dot[i]=be[i]=i;
		for(int i=1;i<=m;i++)
			uu[i]=read(),vv[i]=read(),cc[i]=read();
	}

	inline void add(){
		for(int i=1;i<=m;i++){
			flow.add(uu[i],vv[i],cc[i]);
			flow.add(vv[i],uu[i],cc[i]);
		}
	}

	inline int val(int s,int t){
		flow.init(s,t),add();
		return flow.dinic();
	}

	inline void find(int l,int r){
		for(int i=1;i<=flow.tl;i++){
			int u=flow.q[i];
			if(be[u]>=l&&be[u]<=r)vis[u]=1;
		}
	}

	void build(int l,int r){
		if(l>=r)return;
		int ans=val(dot[l],dot[r]);
		a_e(dot[l],dot[r],ans);
		a_e(dot[r],dot[l],ans);
		find(l,r);
		int i=l,j=r,mid=l-1;
		while(i<j){
			while(vis[dot[i]])i++;
			while(!vis[dot[j]])j--;
			if(i>j)break;
			swap(be[dot[i]],be[dot[j]]);
			swap(dot[i],dot[j]);
			i++,j--;
		}
		for(int i=l;i<=r;i++)
			mid+=vis[dot[i]],vis[dot[i]]=0;
		build(l,mid);
		build(mid+1,r);
	}

}tree;

struct LCA{
	
	int er[22],lg[maxn],dep[maxn],anc[22][maxn],dp[22][maxn];

	void dfs(int u,int fa){
		anc[0][u]=fa;
		dep[u]=dep[fa]+1;
		for(int i=tree.head[u];i;i=tree.e[i].nxt){
			int v=tree.e[i].v,w=tree.e[i].w;
			if(v==fa)continue;
			dp[0][v]=w;
			dfs(v,u);
		}
	}

	inline void init(){
		dfs(1,1);
		er[0]=1,lg[0]=-1,dp[0][1]=INF;
		for(int i=1;i<=n;i++)lg[i]=lg[(i>>1)]+1;
		for(int i=1;i<=lg[n];i++)er[i]=er[(i-1)]<<1;
		for(int i=1;i<=lg[n];i++)
			for(int j=1;j<=n;j++){
				anc[i][j]=anc[i-1][anc[i-1][j]];
				dp[i][j]=min(dp[i-1][j],dp[i-1][anc[i-1][j]]);
			}
	}

	inline int ans(int u,int v){
		int Min=INF;
		if(dep[u]>dep[v])swap(u,v);
		int c=dep[v]-dep[u];
		while(c){
			Min=min(Min,dp[lg[c]][v]);
			v=anc[lg[c]][v];
			c-=er[lg[c]];
		}
		if(u==v)return Min;
		for(int i=lg[dep[u]];i>=0;i--){
			if(anc[i][u]==anc[i][v])continue;
			Min=min(Min,min(dp[i][u],dp[i][v]));
			u=anc[i][u],v=anc[i][v];
		}
		return min(Min,min(dp[0][u],dp[0][v]));
	}

}lca;

int main(){
	n=read(),m=read();
	tree.init();
	tree.build(1,n);
    q=read();
	lca.init();
	for(int i=1;i<=q;i++){
		int x=read(),y=read();
		printf("%d\n",lca.ans(x,y));
  	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/wyzwyz/p/12204122.html