BZOJ 2535: [Noi2010]Plane 航空管制2
Description
世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生。最近,小X就因为航空管制,连续两次在机场被延误超过了两小时。对此,小X表示很不满意。 在这次来烟台的路上,小 X不幸又一次碰上了航空管制。于是小 X开始思考关于航空管制的问题。 假设目前被延误航班共有 n个,编号为 1至n。机场只有一条起飞跑道,所有的航班需按某个顺序依次起飞(称这个顺序为起飞序列)。定义一个航班的起飞序号为该航班在起飞序列中的位置,即是第几个起飞的航班。 起飞序列还存在两类限制条件: 第一类(最晚起飞时间限制):编号为 i的航班起飞序号不得超过 ki; 第二类(相对起飞顺序限制):存在一些相对起飞顺序限制(a, b),表示航班 a的起飞时间必须早于航班 b,即航班 a的起飞序号必须小于航班 b 的起飞序号。 小X 思考的第一个问题是,若给定以上两类限制条件,是否可以计算出一个可行的起飞序列。第二个问题则是,在考虑两类限制条件的情况下,如何求出每个航班在所有可行的起飞序列中的最小起飞序号。
Input
第一行包含两个正整数 n和m,n表示航班数目,m表示第二类限制条件(相对起飞顺序限制)的数目。 第二行包含 n个正整数 k1, k2, „, kn。 接下来 m行,每行两个正整数 a和b,表示一对相对起飞顺序限制(a, b),其中1≤a,b≤n, 表示航班 a必须先于航班 b起飞。
Output
由两行组成。
第一行包含 n个整数,表示一个可行的起飞序列,相邻两个整数用空格分隔。
输入数据保证至少存在一个可行的起飞序列。如果存在多个可行的方案,输出任
意一个即可。
第二行包含 n个整数 t1, t2, „, tn,其中 ti表示航班i可能的最小起飞序
号,相邻两个整数用空格分隔。
Sample Input
5 5
4 5 2 5 4
1 2
3 2
5 1
3 4
3 1
4 5 2 5 4
1 2
3 2
5 1
3 4
3 1
Sample Output
3 5 1 4 2
3 4 1 2 1
3 4 1 2 1
题解:
这个题目好难想,首先第一问还是比较套路的,我们对于n个点,连一个反图,拓扑排序一下,丢到一个按照点权排序的大根堆了面,正确性还是比较显然的,我们按照拓扑排序的顺序,那么一定满足了条件二的限制,那么用堆来搞,他们的点权就是他们的承受能力,那么承受能力强的排在后面,如果这样还不行,那么此题一定无解,(为什么正着做是错的我也不知道)。
然后第二问就比较难想了,我们枚举当前要计算答案的点,那么考虑拓扑排序的时候不把他丢到堆里面,直到出现不合法情况的时候,这个时候,就是他最早出现的位置,因为此刻如果还不放他进去,那么必然序列会不合法,所以这个时刻就是这个点的ans.
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #define MAXN 200050 #define RG register using namespace std; struct node{ int id,v; bool operator < (const node&x)const{ return x.v>v; } }; struct edge{ int first; int next; int to; int quan; }a[MAXN*2]; priority_queue<node> q; int v[MAXN],in[MAXN],in2[MAXN],ans[MAXN]; int n,m,num=0; void addedge(int from,int to){ a[++num].to=to; a[num].next=a[from].first; a[from].first=num; } inline void work1(){ for(RG int i=1;i<=n;i++) in2[i]=in[i]; for(RG int i=1;i<=n;i++){ if(!in2[i]) q.push((node){i,v[i]}); } while(!q.empty()){ int now=q.top().id;q.pop(); ans[++num]=now; for(RG int i=a[now].first;i;i=a[i].next){ int to=a[i].to; in2[to]--; if(!in2[to]) q.push((node){to,v[to]}); } } } inline int work2(int k){ while(!q.empty()) q.pop(); for(int i=1;i<=n;i++) in2[i]=in[i]; for(int i=1;i<=n;i++){ if(i!=k&&!in2[i]) q.push((node){i,v[i]}); } for(RG int hh=n;hh>=1;hh--){ if(q.empty()||q.top().v<hh) return hh; int now=q.top().id;q.pop(); for(RG int i=a[now].first;i;i=a[i].next){ int to=a[i].to; in2[to]--; if(!in2[to]&&to!=k) q.push((node){to,v[to]}); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&v[i]); for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); addedge(y,x);in[x]++; } num=0; work1(); for(int i=num;i>=1;i--) printf("%d ",ans[i]);puts(""); for(int i=1;i<=n;i++) printf("%d ",work2(i)); printf("\n"); return 0; }