CF571D Campus(191)

题意

\(n\)个点,维护两个森林,这里\(A,B\)两个森林对应的点都是一样的,相当于对两个森林操作都会影响这\(n\)个点
开始森林里的树都是一个点,\(A,B\)支持合并(但树结构互不影响),\(A\)支持树赋\(0\)\(B\)支持树加值

做法

\(A,B\)分开做,每次合并新建一个虚点,这样相当于把\(n\)个点拍扁了,就比较好维护点集的操作

求出对每次查询最近的一次赋\(0\)操作,然后再在这个区间里算\(B\)修改对该点的贡献
将操作离线下来放在树上就可以做了

有个小\(trick\)就是用树状数组倍增一下求最近的那次赋\(0\)操作

Code(jly)

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 500000;
struct Tree {
    int n;
    vector<int> parent, lc, rc, id;
    vector<vector<int>> mod;
    Tree(int n) {
        parent.assign(2 * n - 1, -1);
        lc.assign(2 * n - 1, -1);
        rc.assign(2 * n - 1, -1);
        id.resize(n);
        iota(id.begin(), id.end(), 0);
        mod.resize(2 * n - 1);
    }
};
long long fen[N + 1];
void add(int x, int y) {
    for (int i = x + 1; i <= N; i += i & -i)
        fen[i] += y;
}
long long sum(int x) {
    long long res = 0;
    for (int i = x; i > 0; i -= i & -i)
        res += fen[i];
    return res;
}
long long sum(int l, int r) {return sum(r) - sum(l);}
int getLeft(int x) {
    int s = sum(x);
    x = 0;
    for (int i = 1 << 18; i > 0; i /= 2) {
        if (x + i <= N && fen[x + i] < s) {
            x += i;
            s -= fen[x];
        }
    }
    return x;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    Tree t1(n), t2(n);
    vector<vector<int>> query(n);
    vector<int> lb(m), sz(2 * n - 1, 1);
    vector<long long> ans(m, -1);
    int c1 = 0, c2 = 0;
    for (int i = 0; i < m; ++i) {
        char op;
        cin >> op;
        if (op == 'U') {
            int a, b;
            cin >> a >> b;
            --a;
            --b;
            int p = n + (c1++);
            t1.parent[t1.id[a]] = t1.parent[t1.id[b]] = p;
            t1.lc[p] = t1.id[a];
            t1.rc[p] = t1.id[b];
            t1.id[a] = p;
            sz[p] = sz[t1.lc[p]] + sz[t1.rc[p]];
        } else if (op == 'M') {
            int a, b;
            cin >> a >> b;
            --a;
            --b;
            int p = n + (c2++);
            t2.parent[t2.id[a]] = t2.parent[t2.id[b]] = p;
            t2.lc[p] = t2.id[a];
            t2.rc[p] = t2.id[b];
            t2.id[a] = p;
        } else if (op == 'A') {
            int x;
            cin >> x;
            --x;
            t1.mod[t1.id[x]].push_back(i);
        } else if (op == 'Z') {
            int x;
            cin >> x;
            --x;
            t2.mod[t2.id[x]].push_back(i);
        } else {
            int x;
            cin >> x;
            --x;
            query[x].push_back(i);
        }
    }
    function<void(int)> dfs1 = [&](int u) {
        for (int i : t2.mod[u])
            add(i, 1);
        if (u < n) {
            for (int i : query[u])
                lb[i] = getLeft(i);
        } else {
            dfs1(t2.lc[u]);
            dfs1(t2.rc[u]);
        }
        for (int i : t2.mod[u])
            add(i, -1);
    };
    function<void(int)> dfs2 = [&](int u) {
        for (int i : t1.mod[u])
            add(i, sz[u]);
        if (u < n) {
            for (int i : query[u])
                ans[i] = sum(lb[i], i);
        } else {
            dfs2(t1.lc[u]);
            dfs2(t1.rc[u]);
        }
        for (int i : t1.mod[u])
            add(i, -sz[u]);
    };
    for (int i = 0; i < n + c2; ++i)
        if (t2.parent[i] == -1)
            dfs1(i);
    for (int i = 0; i < n + c1; ++i)
        if (t1.parent[i] == -1)
            dfs2(i);
    for (int i = 0; i < m; ++i)
        if (ans[i] != -1)
            cout << ans[i] << "\n";
    return 0;
}
原文地址:https://www.cnblogs.com/Grice/p/12247775.html