suxxsfe

一言(ヒトコト)

CF883B Berland Army

http://codeforces.com/problemset/problem/883/B

给有向图,某些点点权已知,确定其他未知点权,使得:

  1. 所有点权在 \([1,k]\) 之间
  2. 对于边 \(x\rightarrow y\)\(x\) 的点权大于 \(y\)
  3. 对于所有的 \(i\in [1,k]\),都有至少一个点点权为 \(i\)

考虑先正反两边找到每一个点的最大、最小点权,记为 \([l_u,r_u]\)。然后对于每个 \(i\) 确定哪些点的点权为 \(i\),使得在不违反条件 2 的情况下尽量去满足条件 3
此时点权 \([1,i-1]\) 必然已经被分配完,记 \(S\) 为所有 \(l_u\le i\)\(u\) 的集合
那么对于所有的 \(r_u=i\)\(u\),都要分配点权为 \(i\)。因为如果分配成 \(j<i\) 的话,由于存在已经被分配成 \(j\) 的点,可能会产生冲突违反条件 2。而显然把他们分配为 \(i\) 也更符合条件 3
若不存在 \(r_u=i\) 的点,则需要取一个 \(r_u>i\) 的点分配为 \(i\)。此时对于条件 3,显然取 \(r_u\) 最小的最优
如果此时仍然没有 \(r_u>i\) 的点,则为无解

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<utility>
#include<set>
#define reg register
#define EN puts("")
#define INT_INF ((int)0x3f3f3f3f)
#define LL_INF ((long long)0x3f3f3f3f3f3f3f3f)
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
#define N 200006
#define M 200006
struct Graph{
	int fir[N],nex[M],to[M],tot;
	inline void add(int u,int v){
		to[++tot]=v;
		nex[tot]=fir[u];fir[u]=tot;
	}
};
Graph G,T;
int n,m,k;
int val[N];
int in[N],out[N];
int min[N],max[N],id[N];
int left,right,que[N];
inline int topo1(){
	left=0;right=-1;
	for(reg int i=1;i<=n;i++)if(!out[i]) min[i]=val[i]?val[i]:1,que[++right]=i;
	reg int u,i,v;while(left<=right){
		u=que[left++];
		for(i=T.fir[u];i;i=T.nex[i]){
			v=T.to[i];
			min[v]=std::max(min[v],min[u]+1);
			if(!--out[v]){
				if(val[v]&&val[v]<min[v]) return 1;
				min[v]=std::max(min[v],val[v]);
				que[++right]=v;
			}
		}
	}
	for(reg int i=1;i<=n;i++)if(out[i]) return 1;
	return 0;
}
inline int topo2(){
	left=0;right=-1;
	for(reg int i=1;i<=n;i++){
		if(!in[i]) max[i]=val[i]?val[i]:k,que[++right]=i;
		else max[i]=k;
	}
	reg int u,i,v;while(left<=right){
		u=que[left++];
		for(i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			max[v]=std::min(max[v],max[u]-1);
			if(!--in[v]){
				if(val[v]&&val[v]>max[v]) return 1;
				if(val[v]) max[v]=std::min(max[v],val[v]);
				que[++right]=v;
			}
		}
	}
	for(reg int i=1;i<=n;i++)if(in[i]) return 1;
	return 0;
}
int ans[N];
std::set<std::pair<int,int> >set;
int main(){
	n=read();m=read();k=read();
	for(reg int i=1;i<=n;i++) val[i]=read();
	for(reg int u,v,i=1;i<=m;i++){
		u=read();v=read();
		in[v]++;out[u]++;
		G.add(u,v);T.add(v,u);
	}
	if(topo1()||topo2()) return puts("-1"),0;
	for(reg int i=1;i<=n;i++)if(min[i]>max[i]) return puts("-1"),0;
//		for(reg int i=1;i<=n;i++) printf("%d : [%d %d]\n",i,min[i],max[i]);
	for(reg int i=1;i<=n;i++) id[i]=i;
	std::sort(id+1,id+1+n,[](reg int a,reg int b){return min[a]==min[b]?max[a]<max[b]:min[a]<min[b];});
	for(reg int now=1,i=1;i<=k;i++){
		while(now<=n&&min[id[now]]<=i) set.insert(std::make_pair(max[id[now]],id[now])),now++;
		int have=0;
		while(!set.empty()){
			int id=(*set.begin()).second;
			if(have&&max[id]>i) break;
			ans[id]=i;have=1;
			set.erase(set.begin());
		}
		if(!have) return puts("-1"),0;
	}
	for(reg int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
}
posted @ 2021-07-11 08:27  suxxsfe  阅读(76)  评论(0编辑  收藏  举报