• 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;
    }
    
  • 相关阅读:
    用命令行工具安装 卸载 设置 .Net服务
    oracle imp 数据时实现插入到表中 不覆盖
    Oracle导出 Exp的使用
    Linux下的tar压缩解压缩命令详解
    设计模式 配置器
    设计模式 概括说明
    设计模式 创建型模式
    设计模式 组成 & 装饰 & 外观
    设计模式 单件 & 原型
    设计模式 享元 & 代理
  • 原文地址:https://www.cnblogs.com/Grice/p/12247775.html
Copyright © 2020-2023  润新知