POI2011 MET-Meteors 整體二分
阿新 • • 發佈:2022-03-31
MET-Meteors
知識點 : 整體二分
如果考慮對每個顏色進行二分,那麼時間複雜度將會達到\(O(nmlogm)\),這個複雜度甚至超過了直接暴力的做法,顯然時不可行的。
這個時候我們就需要一種新的思路,那就是整體二分。
整體二分,又稱並行二分,顧名思義,就是將多個值同時進行二分。具體的操作流程如下。
以值域範圍為\([1,n]\)為例,一開始所有的值的查詢位置都在\(mid = \frac{l + r}{2}=\frac{n}{2}\),我們遍歷\(1\)到\(n\),在\(\frac{n}{2}\)處處理了所有的check,並將每一個值的\([l,r]\)更新,得到新的\(mid\)
根據我們已有的知識,二分只需要\(logn\)次操作就可以得到答案,所以我們上述操作中,遍歷1到n也只會執行\(logn\)次。如果有\(k\)個數需要二分,總時間複雜度就為\(O(logn (n + k*O(check))\)(這個複雜度是我口胡的,如有錯誤請指出)
回到本題中,我們對於每一個顏色進行整體二分,二分第幾次修改能夠達到要求,我們用樹狀陣列來實現區間加,單點查詢。對於每一輪的更新,因為\([1,m]\)所有位置都會被查詢僅一次,所以複雜度中\(O(k*O(check))\)部分即為\(O(mlogm)\),所以整體時間複雜度粗略估計為\(O(logn*mlogm))\),在這個時間複雜度下,我們就可以通過此題。
貼一個核心程式碼
bool check(int c) { ull res = 0; for (auto i : bel[c]) { res += t1.query(i); } return res >= p[c]; } void solve() { //qs為一次修改的結構體陣列,包含l,r,c //t1為一個樹狀陣列 int cnt = 1; while (cnt != 0) { cnt = 0; for (int i = 1; i <= k; i++) { if (qs[i].l <= qs[i].r) t1.update(qs[i].l, qs[i].r, qs[i].c); else { t1.update(qs[i].l, m, qs[i].c); t1.update(1, qs[i].r, qs[i].c); } for (auto c : ask[tp][i]) { if (check(c)) { res[c] = i; r[c] = i - 1; } else l[c] = i + 1; if (l[c] <= r[c]) { mid[c] = (l[c] + r[c]) / 2; ask[tp ^ 1][mid[c]].emplace_back(c); cnt++; } } ask[tp][i].clear(); } t1.init(); tp ^= 1; } }