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;
    }
}
posted @ 2022-03-31 19:38  icey_z  阅读(47)  评论(0)    收藏  举报