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

正题

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


题目大意

\(n\) 个点,每个点有个初始权值 \(a_i\) ,你每次可以让一个点权值 \(+1\) 或者 \(-1\)

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

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

\(2\leq n,m\leq 1000,1\leq a_i\leq 10^9\)


解题思路

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

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


code

#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;
}
posted @ 2024-08-13 09:50  QuantAsk  阅读(15)  评论(0编辑  收藏  举报