程式碼源每日一題Div2 106 訂單編號 題解
阿新 • • 發佈:2022-05-11
簡要題意
給定 \(n\) 個訂單,第 \(i\) 個訂單的編號為 \(a_i\)。
現在我們需要對訂單進行重新編號,從前到後依次進行,要求對於任意一個訂單,必須要選擇一個大於等於舊編號,並沒被用過(是指在新編號中沒被用過,也就是說這些新編號要互不相同)的最小正整數作為新編號。
模擬完後,依次輸出這些訂單的新編號。
\(n\leq 5*10^5,1\leq a_i\leq 10^9\)
題解
本題就是 set 維護區間的經典應用,如下:
- 設立一個存放區間的 set,按照右端點大小來排序
- 按照順序重新定下編號,對於原來編號 \(x\),找區間 \([L,R]\),\(R\) 應當在大於等於 \(x\)
- 給這個訂單定一個新編號 \(\max(L,x)\),並將這個區間進行拆分,隨後再 insert 進去
總複雜度約為 \(O(\sum\limits_{i=1}^n(1+\log i))=O(n\log n)\)。
#include<bits/stdc++.h> using namespace std; set<pair<int, int> > s; void insert(int L, int R) { if (L > R) return; s.insert(make_pair(R, L)); } int main() { insert(1, 2e9); int n; scanf("%d", &n); for (int i = 1, x; i <= n; ++i) { scanf("%d", &x); auto it = s.lower_bound(make_pair(x, 0)); int res = max(x, it->second); insert(it->second, res - 1); insert(res + 1, it->first); printf("%d ", res); s.erase(it); } return 0; }