1. 程式人生 > 其它 >POI2011 MET-Meteors 整體二分

POI2011 MET-Meteors 整體二分

MET-Meteors

知識點 : 整體二分

​ 如果考慮對每個顏色進行二分,那麼時間複雜度將會達到\(O(nmlogm)\),這個複雜度甚至超過了直接暴力的做法,顯然時不可行的。

​ 這個時候我們就需要一種新的思路,那就是整體二分。

​ 整體二分,又稱並行二分,顧名思義,就是將多個值同時進行二分。具體的操作流程如下。

​ 以值域範圍為\([1,n]\)為例,一開始所有的值的查詢位置都在\(mid = \frac{l + r}{2}=\frac{n}{2}\),我們遍歷\(1\)\(n\),在\(\frac{n}{2}\)處處理了所有的check,並將每一個值的\([l,r]\)更新,得到新的\(mid\)

,即\(\frac{n}{4}\)\(\frac{3n}{4}\)。然後我們重複同樣的做法,遍歷\(1\)\(n\),並在新的\(mid\)處進行check並插入到新的位置\(\frac{n}{8},\frac{3n}{8},\frac{5n}{8},\frac{7n}{8}\),然後以此類推...最終我們就會得到所有值最終的位置。

​ 根據我們已有的知識,二分只需要\(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;
    }
}