您的位置:首页 > 房产 > 建筑 > CF1615H-Reindeer Games【保序回归,整体二分,网络流】

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

2024/12/25 21:10:20 来源:https://blog.csdn.net/Mr_wuyongcong/article/details/141094109  浏览:    关键词: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 2n,m1000,1ai109


解题思路

对于这类的保序回归问题,我们可以考虑整体二分,当前枚举到 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 bxby ,那么当 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

#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;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com