NOI2010 航空管制

2022-05-20 14:37:48 字數 2166 閱讀 9099

對於第一問,對於每條限制 \((u, v)\) 我們連邊 \(v \rightarrow u\),這樣將構成一張 \(\rm dag\)。首先先拓撲排序,對於拓撲序考前的點我們先讓他盡量往後放,顯然這樣是最優的,因為我們在偏序滿足條件的情況下讓每個點盡量後放以保證方案的合法性,但需要注意的一點是可能拓撲序大的點能放的位置比較靠後而拓撲序小的點能放的位置比較靠前,那麼這樣兩個都盡量後放就不滿足偏序關係了,因此我們在拓撲排序時需要先進行一遍 \(a_v = \min\\) 以保證後面的點能放的位置在 \(u\) 前。

上面那個找到某個位置左邊第乙個沒有放東西的位置可以使用線段樹來實現。具體地我們將當前每個選過的位置上標號為選它的點,沒選的位置標號為 \(0\),那麼我需要查詢的實際上是某個位置往左第乙個是 \(0\) 的位置,注意到所有權值都是非負的,那麼如果一段區間內最小值為 \(0\) 那麼就說明這段區間內肯定出現了 \(0\) 反之則沒有出現 \(0\),於是我們可以使用線段樹維護區間最小值,每個區間記錄兩個值 \(min, p\),分別為這個區間內的最小值和最右邊的 \(0\) 的位置,沒有 \(0\) 則 \(p = 0\),顯然這個東西是可以左右兩個區間合併的。那麼我們每次相當於只要查詢 \(1 \sim x\) 這個字首中最大的 \(p\) 就可以知道 \(x\) 左邊第乙個為 \(0\) 的位置了,當然這個方法還使用於查區間第乙個為 \(0\) 的位置。同樣這個方法也可以來做查詢左邊第乙個比他小的位置。

再來考慮第二問,觀察一下上面我們拓撲排序的過程,實際上是讓一部分點盡量靠後,那麼我們為了讓 \(x\) 放得盡可能靠前,可以直接先不考慮 \(x\) 和他能遍歷到的點,讓別的點盡量靠後,再最後查詢一下當前序列最後能放的位置就是 \(x\) 能放的最前位置。複雜度 \(o(n ^ 2 \log n + nm)\)

加了火車頭才過的。

#includeusing namespace std;

#define n 2000 + 5

#define m 10000 + 5

#define ls (p << 1)

#define rs (p << 1 | 1)

#define mid (l + r) / 2

#define rep(i, l, r) for(register int i = l; i <= r; ++i)

#define next(i, u) for(register int i = h[u]; i; i = e[i].next)

struct treet[n << 4];

struct edgee[m];

int n, m, u, v, tot, a[n], h[n], d[n], p[n], ans[n], index[n];

queue q;

inline int read()

while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();

return x * f;

}inline void add(int u, int v)

inline void build(int p, int l, int r)

inline void update(int p, int l, int r, int x, int y, int k)

if(mid >= x) update(ls, l, mid, x, y, k);

if(mid < y) update(rs, mid + 1, r, x, y, k);

t[p].min = min(t[ls].min, t[rs].min);

if(!t[rs].min) t[p].p = t[rs].p;

else if(!t[ls].min) t[p].p = t[ls].p;

else t[p].p = 0;

}inline int query(int p, int l, int r, int x, int y)

int solve(int p)

}return query(1, 1, n, 1, a[p]);

}int main()

}rep(i, 1, n) p[ans[i]] = i;

rep(i, 1, n) printf("%d ", p[i]); puts("");

rep(i, 1, n) printf("%d ", solve(i));

return 0;

}

NOI2010 航空管制

二元組的限制 考慮拓撲排序 正向拓撲不能保證最優,因卡的是結束時間 所以方向建圖topo 從n為0時間,相當於在n k i 的時間出現一架飛機 小根堆維護,每次選擇當前最早出現的一架飛機起飛。由於保證有解,這個顯然是正確的,對於當前只有一架飛機,不飛白不飛 當然也不能不飛 多架飛機,先飛後飛反正都是...

NOI2010 航空管制

首先第一問是很好做的,因為題目中保證有合法解,所以我們盡量讓期限晚的航班晚起飛.所以就是反著建圖,按照拓撲序給每個航班安排時間.第二問要求問所有合法解中每個航班最早什麼時候能起飛.那麼還是參考第一問的思路,額外的一點就是讓能安排在它後面的航班都安排到後面.所以就是先限制不選它,直到剩下的沒有辦法再選...

NOI2010 航空管制

貪心。對於第1個問,我們先建立拓撲圖,對於如果a必須在b前起飛,那麼連有向邊b a,並求出點的入度。將所有入度為0的點放在乙個優先佇列裡,按最大起飛編號從大到小排序。我們從後往前考慮起飛的航班。取出優先佇列中最大起飛編號最大的點,作為最後乙個航班,並刪去拓撲圖中與他相連的邊,如果有新的點的入度變成0...