题目
思路
这题思路还是很妙的,考虑把所有的
a
a
a抽象成n个点,然后进行二分答案。
设现在这个点集为
V
V
V,我们本质上在二分这个点集所有点的最终取值。
那么接下来,我们要解决的问题就是,如何对点集进行二分。
可以这样做,新建一个源点和一个汇点,然后开始建模。
对于点集中每个点的初始值,我们将其和mid比较,大的与t连容量为1的边,小的与s连容量为1的边。
原图的约束条件在建模时连容量inf的边。
接下来跑一次网络流,就会得到一个残量网络。
现在研究一下这个残量网络的性质。
如果2个非源汇点之间有边,说明该边联通的2点无法在一个大于mid,一个小于等于mid的情况下满足约束。
如果一个点对源点而言可达,必定与汇点不可达,就说明这个点的最优答案比mid更小,反之更大。
因此我们就完成了点集划分,本题完结。
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
int n,m,s,t,x,y,tot=2,head[2001],cur[2001],dep[2001],l,r,u[2001],r2;
long long w,ans[2001],aa[2001];
long long mn(long long x,long long y)
{
return (x>y?y:x);
}
struct f{
int to,net;
long long w;
} a[1000011];
void add(int x,int y,long long w)
{
a[tot].to=y,a[tot].w=w,a[tot].net=head[x],head[x]=tot++;
return;
}
bool bfs()
{
memset(dep,-1,sizeof(dep));
queue<int> u;
u.push(s);
dep[s]=0;
while (u.size())
{
int x=u.front();
u.pop();
for (int j=head[x];j;j=a[j].net)
{
if (a[j].w>0&&dep[a[j].to]==-1)
{
u.push(a[j].to);
dep[a[j].to]=dep[x]+1;
}
}
}
return dep[t]!=-1;
}
long long dfs(int d,long long in)
{
if (d==t) return in;
long long out=0;
int uw=dep[d]+1;
for (int &j=cur[d];j&∈j=a[j].net)
{
if (a[j].w<=0||dep[a[j].to]!=uw) continue;
long long s=dfs(a[j].to,mn(in,a[j].w));
out+=s,in-=s;
a[j].w-=s,a[j^1].w+=s;
}
if (out==0)
{
dep[d]=0;
}
return out;
}
void Dinic()
{
while (bfs())
{
memcpy(cur,head,sizeof(cur));
while (1)
{
if (!dfs(s,1e9)) break;
}
}
return;
}
int newid[2000];
vector<int> edg[2000];
void solve(vector<int> V,long long l,long long r)//The value of each point in point set V is between L and r
{
if (l==r)
{
for (int i=0;i<V.size();i++) ans[V[i]]=l;
return;
}
if (!V.size()) return;
for (int i=0;i<V.size();i++) newid[V[i]]=i+1;
n=V.size()+1,s=0,t=n,tot=2;
for (int i=0;i<=n;i++) head[i]=0;
for (int i=0;i<V.size();i++)
{
int x=V[i];
for (int j=0;j<edg[x].size();j++)
{
if (!newid[edg[x][j]]) continue;
add(i+1,newid[edg[x][j]],1e9);
add(newid[edg[x][j]],i+1,0);
}
}//remake
long long mid=l+r>>1;
for (int i=0;i<V.size();i++)
{
int u=V[i];
if (mid<aa[u]) add(s,i+1,1),add(i+1,s,0);
else add(i+1,t,1),add(t,i+1,0);
}
Dinic();
vector<int> LV,RV;
for (int i=0;i<V.size();i++)
{
if (dep[i+1]!=-1) RV.push_back(V[i]);
else LV.push_back(V[i]);
}//divide
for (int i=0;i<V.size();i++) newid[V[i]]=0;
solve(LV,l,mid);
solve(RV,mid+1,r);
return;
}
int main()
{
int n,m;
cin>>n>>m;
for (int i=1;i<=n;i++) scanf("%lld",&aa[i]);
for (int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
edg[x].push_back(y);
}
vector<int> U;
for (int i=1;i<=n;i++) U.push_back(i);
solve(U,1,1e9);
for (int i=1;i<=n;i++) printf("%lld ",ans[i]);
return 0;
}