1. 程式人生 > 其它 >#貪心,二叉堆#洛谷 1954 [NOI2010] 航空管制

#貪心,二叉堆#洛谷 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;
}