常见的套路与不常见的套路
第一问是常见的套路,建反边用优先队列跑拓扑排序
第二问是不常见的套路,如何判断一个点最早什么时候起飞?先不加它来拓扑排序,直到拓扑排序不能进行下去了,这个时刻就是它必须加入的时刻。因为我们是反着做的,所以这样求出来的就是最早时刻。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // luogu-judger-enable-o2 2 #include<queue> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 const int N=2005,M=10005; 8 int n,m,t1,t2,cnt,top; 9 int p[N],noww[M],goal[M]; 10 int mem[N],deg[N],lst[N],stk[N],que[N]; 11 priority_queue<pair<int,int> > hp; 12 void Clean() 13 { 14 priority_queue<pair<int,int> > tmp; 15 swap(hp,tmp); 16 } 17 void Link(int f,int t) 18 { 19 noww[++cnt]=p[f],p[f]=cnt; 20 goal[cnt]=t,mem[t]++; 21 } 22 int Solve(int nde) 23 { 24 Clean(); 25 for(int i=1;i<=n;i++) 26 if(!(deg[i]=mem[i])&&i!=nde) 27 hp.push(make_pair(lst[i],i)); 28 deg[nde]=n; 29 for(int i=n;i;i--) 30 { 31 if(hp.empty()) return i; 32 pair<int,int> tn=hp.top(); hp.pop(); 33 if(tn.first<i) return i; 34 for(int i=p[tn.second];i;i=noww[i]) 35 if(!(--deg[goal[i]])) 36 hp.push(make_pair(lst[goal[i]],goal[i])); 37 } 38 } 39 int main() 40 { 41 scanf("%d%d",&n,&m); 42 for(int i=1;i<=n;i++) 43 scanf("%d",&lst[i]); 44 for(int i=1;i<=m;i++) 45 scanf("%d%d",&t1,&t2),Link(t2,t1); 46 for(int i=1;i<=n;i++) 47 if(!(deg[i]=mem[i])) hp.push(make_pair(lst[i],i)); 48 while(!hp.empty()) 49 { 50 pair<int,int> tn=hp.top(); 51 hp.pop(),stk[++top]=tn.second; 52 for(int i=p[tn.second];i;i=noww[i]) 53 if(!(--deg[goal[i]])) 54 hp.push(make_pair(lst[goal[i]],goal[i])); 55 } 56 while(top) printf("%d ",stk[top--]); puts(""); 57 for(int i=1;i<=n;i++) printf("%d ",Solve(i)); 58 return 0; 59 }