#贪心,二叉堆#洛谷 1954 [NOI2010] 航空管制

题目


分析

首先考虑可行方案,很容易想到拓扑排序,

但是如果建正图第一类的限制有可能不能满足,

考虑第一类限制其实时间倒流就是在 \(T\) 时刻之后才能选它。

那么直接建反图然后 \(a_i\) 大的优先选,可以用二叉堆来维护。

考虑最早起飞时间那么将反图中这个点的后继全部提出来(正过来看就是这些点是它的祖先)

那么其它点由于满足了第一类限制所以顺序可以固定,然后将这些后继包括本身依次合法插入即可


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;
const int N=2011; priority_queue<pair<int,int> >q;
struct node{int y,next;}e[N*5];
int v[N],st[N],n,m,b[N],as[N],a[N],mn[N],ans,tot,upd,deg[N];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48); 
}
void dfs(int x){
	v[x]=upd;
	for (int i=as[x];i;i=e[i].next)
	    if (v[e[i].y]!=upd) dfs(e[i].y);
}
int main(){
	n=iut(),m=iut();
	for (int i=1;i<=n;++i) a[i]=iut();
	for (int i=1;i<=m;++i){
		int y=iut(),x=iut();
		e[i]=(node){y,as[x]},as[x]=i,++deg[y];
	}
	for (int i=1;i<=n;++i)
	    if (!deg[i]) q.push(make_pair(a[i],i));
	while (!q.empty()){
		int x=q.top().second; st[++st[0]]=x; q.pop();
		for (int i=as[x];i;i=e[i].next)
		    if (!(--deg[e[i].y])) q.push(make_pair(a[e[i].y],e[i].y));
	}
	reverse(st+1,st+1+n);
	for (int i=1;i<=n;++i) print(st[i]),putchar(i==n?10:32);
	for (int i=1;i<=n;++i){
		tot=0,ans=1,++upd,dfs(i);
		for (int j=1;j<=n;++j)
		    if (v[st[j]]!=upd) b[++tot]=st[j];
		mn[tot+1]=0x3f3f3f3f;
		for (int j=tot;j;--j)
		    mn[j]=min(mn[j+1],a[b[j]]-j);
		for (int j=1;j<=n-tot;++j)
			for (;ans<=tot&&mn[ans]<j;++ans);
		print(ans+n-tot-1),putchar(i==n?10:32);
	}
	return 0;
}
posted @ 2021-12-21 17:12  lemondinosaur  阅读(38)  评论(0编辑  收藏  举报