CF1615H-Reindeer Games【保序回归,整体二分,网络流】

正题

题目链接:https://www.luogu.com.cn/problem/CF1615H


题目大意

有 n n n 个点,每个点有个初始权值 a i a_i ai ,你每次可以让一个点权值 + 1 +1 +1 或者 − 1 -1 −1 。

有 m m m 个限制要求某个点最终权值小于等于另一个点。

求最少的操作次数使得满足所有限制。

2 ≤ n , m ≤ 1000 , 1 ≤ a i ≤ 1 0 9 2\leq n,m\leq 1000,1\leq a_i\leq 10^9 2≤n,m≤1000,1≤ai≤109


解题思路

对于这类的保序回归问题,我们可以考虑整体二分,当前枚举到 m i d mid mid 时我们考虑将点权设为 m i d mid mid 或者 m i d + 1 mid+1 mid+1 时的最优情况,如果在这种情况下某个点被设置为 m i d mid mid 则最终值在 [ l , m i d ] [l,mid] [l,mid] 中,否则在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 中。

然后我们考虑用网络流解决设置点权的问题,如果要求 b x ≤ b y b_x\leq b_y bx≤by ,那么当 b x b_x bx 被设置为 m i d + 1 mid+1 mid+1 时 b y b_y by 也要被设置为 m i d + 1 mid+1 mid+1 ,可以将题目变为一个最大权闭合图问题,使用网络流解决即可。


code

cpp 复制代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
const ll N=1100;
ll n,m,s,t,a[N],p[N],b[N];
ll pos[N],c[N],np[N],ans[N];
vector<ll> G[N];
namespace Net{
	struct node{
		ll to,next,w;
	}a[N<<2];
	ll dep[N],ls[N],tot,cnt;
	queue<ll> q;
	void addl(ll x,ll y,ll w){
		a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
		a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
	}
	bool bfs(){
		while(!q.empty())q.pop();
		for(ll i=1;i<=cnt;i++)dep[i]=0;
		q.push(s);dep[s]=1;
		while(!q.empty()){
			ll x=q.front();q.pop();
			for(ll i=ls[x];i;i=a[i].next){
				ll y=a[i].to;
				if(dep[y]||!a[i].w)continue;
				dep[y]=dep[x]+1;q.push(y);
				if(y==t)return true;
			}
		}
		return false;
	}
	ll dinic(ll x,ll flow){
		if(x==t)return flow;
		ll rest=0,k;
		for(ll i=ls[x];i;i=a[i].next){
			ll y=a[i].to;
			if(!a[i].w||dep[x]+1!=dep[y])continue;
			rest+=(k=dinic(y,min(a[i].w,flow-rest)));
			a[i].w-=k;a[i^1].w+=k;
			if(rest==flow)return rest;
		}
		if(!rest)dep[x]=0;
		return rest;
	}
	ll solve(){
		ll ans=0;
		while(bfs())
			ans+=dinic(s,1e18);
		bfs();
		return ans;
	}
	void init(){
		for(ll i=1;i<=cnt;i++)ls[i]=0;
		tot=1;s=1;t=2;
		return;
	}
}
void solve(ll l,ll r,ll L,ll R){
	if(l>r)return;
	if(L==R){
		for(ll i=l;i<=r;i++)ans[p[i]]=b[L];
		return;
	}
	ll mid=(L+R)>>1;
	Net::init();
	for(ll i=l;i<=r;i++){
		ll x=p[i];pos[x]=i;
		c[i]=abs(a[x]-b[mid])-abs(a[x]-b[mid+1]);
		if(c[i]>0)Net::addl(s,3+i-l,c[i]);
		else Net::addl(3+i-l,t,-c[i]);
	}
	for(ll i=l;i<=r;i++){
		ll x=p[i];
		for(ll z=0;z<G[x].size();z++)
			if(pos[G[x][z]]>=l&&pos[G[x][z]]<=r){
				ll j=pos[G[x][z]];
				Net::addl(3+i-l,3+j-l,1e18);
			}
	}
	for(ll i=l;i<=r;i++)pos[p[i]]=0;
	Net::cnt=3+r-l;
	Net::solve();
	ll xl=l,xr=r;
	for(ll i=l;i<=r;i++){
		if(Net::dep[3+i-l])np[xr--]=p[i];
		else np[xl++]=p[i];
	}
	for(ll i=l;i<=r;i++)p[i]=np[i];
	solve(l,xl-1,L,mid);
	solve(xr+1,r,mid+1,R);
	return;
}
signed main()
{
	ll k;
	scanf("%lld%lld",&n,&k);
	for(ll i=1;i<=n;i++)scanf("%lld",&a[i]),p[i]=i,b[i]=a[i];
	sort(b+1,b+1+n);
	m=unique(b+1,b+1+n)-b-1;
	for(ll i=1,x,y;i<=k;i++){
		scanf("%lld%lld",&x,&y);
		G[x].push_back(y);
	}
	solve(1,n,1,m);
	for(ll i=1;i<=n;i++)printf("%lld ",ans[i]);
	return 0;
}
相关推荐
Timmylyx05184 天前
Codeforces Round 1075 (Div. 2) 题解
算法·codeforces·比赛日记
Timmylyx05181 个月前
CF 新年赛 Goodbye 2025 题解
算法·codeforces·比赛日记
Timmylyx05181 个月前
2025年最后一搏—— Educational Codeforces Round 186 (Rated for Div. 2) 题解
算法·codeforces·比赛日记
ddmdd2 个月前
codeforces Round 1070(Div. 2)
codeforces
hansang_IR2 个月前
【记录】网络流最小割建模三题
c++·算法·网络流·最小割
defaulter3 个月前
Codeforces Round 1049 (Div. 2)C. Ultimate Value
算法·codeforces
CUC-MenG3 个月前
2025牛客国庆集训派对day5 K E 个人题解
图论·网络流·状态压缩·随机优化·树上dp·网络流费用流
悟乙己5 个月前
保序回归Isotonic Regression的sklearn实现案例
数据挖掘·回归·sklearn·保序回归
图灵信徒5 个月前
ICPC Central Russia Regional Contest, 2024
c++·python·codeforces·算法竞赛
超闻逸事6 个月前
题解:CF2129C Interactive RBS
c++·算法·codeforces