题解:[ARC142E] Pairing Wizards

前言

建议收录于新网络流 24 题。

这个拆点是魔法吧。

思路分析

不失一般性,令 \(b_x \le b_y\),那么原限制转化为:

  • \(a_x \ge b_x\)\(a_y \ge b_x\)

  • \(a_x \ge b_y\)\(a_y \ge b_y\)

对于第一条限制,我们令 \(x\) 的初始点权为 \(c_x=a_x\),让 \(c_x,c_y\) 每次和 \(b_y\)\(\max\)

那么我们实际上只剩下了第二条限制,因为这个形式是二选一,所以我们考虑最小割。

\(a_x \ge b_x\) 是好做的,对于每个点 \(x\),连边 \((s,x,b_x-c_x)\),如果这条边被割了,说明我们满足的是第一种可能;

\(a_y \ge b_x\) 的问题在于,如果有多个对 \(y\) 的限制,我们很容易算重。

然后是魔法时刻!

考虑对右部点 \(x\) 按值域拆点,\((y,v)\) 表示 \(y\) 点权为 \(c_y+v\) 的状态,对于 \(a_x \ge b_y\) 的限制,我们需要连边 \((y,(x,b_y-c_x),+\infty)\)

对于右部点内部,连边 \(((x,v-1),(x,v),+\infty),((x,v),t,1)\)

这样我们右部点割到了 \((x,v)\) 就表示 \(x\) 此时真正的点权为 \(c_x+v\)

原图的最小割加上 \(\sum_{x=1}^{n} c_x-a_x\) 就是答案。

复杂度 \(O(能过)\)

代码实现

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int maxn=100;
int n,m,s,t,ans,a[105],b[105],c[105],x[10005],y[10005],L[105],R[105][105],dcnt;
int head[200005],nxt[200005],targetx[200005],targetw[200005],targetf[200005],tot=1;
void add(int x,int y,int w,int f){
	tot++;
	nxt[tot]=head[x];
	head[x]=tot;
	targetx[tot]=y;
	targetw[tot]=w;
	targetf[tot]=f;
}
int dis[200005],now[200005];
queue<int> q;
bool bfs(){
	for(int i=1;i<=dcnt;i++){
		dis[i]=inf;
		now[i]=head[i];
	}
	dis[s]=1;
	q.push(s);
	while(q.size()){
		int x=q.front();
		q.pop();
		for(int i=head[x];i;i=nxt[i]){
			int y=targetx[i],w=targetw[i],f=targetf[i];
			if(dis[y]!=inf || w-f==0) continue;
			dis[y]=dis[x]+1;
			q.push(y);
		}
	}
	return dis[t]!=inf;
}
int dfs(int x,int sum){
	if(x==t) return sum;
	int res=0;
	for(int i=head[x];i;i=nxt[i]){
		int y=targetx[i],w=targetw[i],f=targetf[i];
		if(dis[y]!=dis[x]+1 || w-f==0) continue;
		int tp=dfs(y,min(sum,w-f));
		if(!tp) dis[y]=inf;
		else{
			targetf[i]+=tp;
			targetf[i^1]-=tp;
			sum-=tp;
			res+=tp;
		}
		if(!sum) break;
	}
	return res;
}
int dinic(){
	int  ans=0;
	while(bfs()) ans+=dfs(s,inf);
	return ans;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
		c[i]=a[i];
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i];
		if(b[x[i]]>b[y[i]]) swap(x[i],y[i]);
		c[x[i]]=max(c[x[i]],b[x[i]]);
		c[y[i]]=max(c[y[i]],b[x[i]]);
	}
	s=++dcnt;
	t=++dcnt;
	for(int i=1;i<=n;i++){
		L[i]=++dcnt;
		if(c[i]<b[i]){
			add(s,L[i],b[i]-c[i],0);
			add(L[i],s,0,0);
		}
		R[i][0]=++dcnt;
		for(int j=1;j<=maxn;j++){
			R[i][j]=++dcnt;
			add(R[i][j],t,1,0);
			add(t,R[i][j],0,0);
			add(R[i][j],R[i][j-1],inf,0);
			add(R[i][j-1],R[i][j],0,0);
		}
	}
	for(int i=1;i<=m;i++){
		if(c[x[i]]>=b[y[i]] || c[y[i]]>=b[y[i]]) continue;
		add(L[y[i]],R[x[i]][b[y[i]]-c[x[i]]],inf,0);
		add(R[x[i]][b[y[i]]-c[x[i]]],L[y[i]],0,0);
	}
	for(int i=1;i<=n;i++){
		ans+=c[i]-a[i];
	}
	cout<<ans+dinic();
	return 0;
}
posted @ 2025-04-04 16:44  _Kenma  阅读(18)  评论(0)    收藏  举报