【清华集训2012】【BZOJ2561】最小生成树(最小割)

传送门


解析:

显然就是说 u , v u,v u,v不能直接通过权值大于或小于 L L L的边直接连起来。

那么把权值大于或小于 L L L的边全部拿出来,分别建图。

显然要不使 u , v u,v u,v联通,直接上ISAP跑最小割就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

using std::cout;
using std::cerr;

cs int N=2e4+4,M=2e5+5;
int n,m;
struct edge{
	int to,cap,rev;
	edge(cs int &_to,cs int &_cap,cs int &_rev):
		to(_to),cap(_cap),rev(_rev){}
};

std::vector<edge> G[N];
typedef std::vector<edge>::iterator iter;
iter cur[N];

inline void addedge(int u,int v){
	G[u].push_back(edge(v,1,G[v].size()));
	G[v].push_back(edge(u,1,G[u].size()-1));
}

int S,T;
int lev[N],gap[N];

inline void BFS(){
	memset(lev+1,0,sizeof(int)*n);
	memset(gap,0,sizeof(int)*(n+2));
	lev[T]=gap[1]=1;
	std::queue<int> q;q.push(T);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(iter re e=G[u].begin();e!=G[u].end();++e)
		if(!lev[e->to])++gap[lev[e->to]=lev[u]+1],q.push(e->to); 
	}
}

inline int dfs(int u,cs int &flow){
	if(u==T)return flow;
	int ans=0;
	for(iter &e=cur[u];e!=G[u].end();++e)
	if(e->cap&&lev[e->to]+1==lev[u]){
		int delta=dfs(e->to,std::min(flow-ans,e->cap));
		if(delta){
			e->cap-=delta;
			G[e->to][e->rev].cap+=delta;
			if((ans+=delta)==flow)return flow;
		}
	}
	if(--gap[lev[u]]==0)lev[S]=n+1;
	++gap[++lev[u]];
	return ans;
}

inline int ISAP(){
	BFS();
	int mxflow=0;
	while(lev[S]<=n){
		for(int re i=1;i<=n;++i)cur[i]=G[i].begin();
		mxflow+=dfs(S,0x3f3f3f3f);
	}
	return mxflow;
}

inline void clear(){
	for(int re i=1;i<=n;++i)G[i].clear();
}

struct E{
	int u,v,w;
}e[M];
int L,ans;
signed main(){
	n=getint(),m=getint();
	for(int re i=1;i<=m;++i){
		e[i].u=getint(),e[i].v=getint();
		e[i].w=getint();
	}
	S=getint(),T=getint(),L=getint();
	for(int re i=1;i<=m;++i)if(e[i].w<L)addedge(e[i].u,e[i].v);
	ans=ISAP();
	clear();
	for(int re i=1;i<=m;++i)if(e[i].w>L)addedge(e[i].u,e[i].v);
	cout<<(ans+ISAP())<<"\n";
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值