1 条题解

  • 0
    @ 2025-8-24 21:46:11

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar jiangly
    这个家伙很菜,什么也没有留下

    搬运于2025-08-24 21:46:11,当前版本为作者最后更新于2020-04-12 18:24:00,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意

    给定一个 nn 个点 mm 条边的仙人掌 (1n1051\le n\le 10^5, n1m1.5105n-1\le m\le 1.5\cdot10^5),定义 uu 的子仙人掌为去掉 uu11 的所有简单路径经过的街道后 uu 所在的连通块。每个点有点权,qq (1q1051\le q\le 10^5) 次询问一个点的子仙人掌中出现次数为奇数/偶数的点权个数。

    题解

    进行一遍 dfs, 对于每个环,删掉其中的所有边并从其中 dfs 序最小的点向环上其他所有点连边。容易发现,进行这样的操作后原图变成了一棵树,且这个树上 uu 的子树所包含的点与原图中 uu 的子仙人掌所包含的点相同。问题转化为了子树询问,因此线段树合并即可。

    时间复杂度:O((n+q)logn+m)O((n+q)\log n+m)

    代码

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <functional>
    #include <numeric>
    struct Node {
        Node *lc, *rc;
        int cnt[2];
        Node(Node *lc = nullptr, Node *rc = nullptr, int c0 = 0, int c1 = 0) : lc(lc), rc(rc), cnt{c0, c1} {}
    };
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        int n, m;
        std::cin >> n >> m;
        std::vector<int> a(n);
        for (int i = 0; i < n; ++i)
            std::cin >> a[i];
        auto values = a;
        std::sort(values.begin(), values.end());
        values.erase(std::unique(values.begin(), values.end()), values.end());
        for (auto &i : a)
            i = std::lower_bound(values.begin(), values.end(), i) - values.begin();
        std::vector<std::vector<int>> e(n);
        std::vector<int> parent(n, -1), dep(n, -1);
        for (int i = 0; i < m; ++i) {
            int u, v;
            std::cin >> u >> v;
            --u;
            --v;
            e[u].push_back(v);
            e[v].push_back(u);
        }
        dep[0] = 0;
        std::function<void(int)> dfs = [&](int u) {
            for (auto v : e[u]) {
                if (v == parent[u])
                    continue;
                if (dep[v] == -1) {
                    parent[v] = u;
                    dep[v] = dep[u] + 1;
                    dfs(v);
                } else if (dep[v] > dep[u]) {
                    for (auto i = v; i != u; )
                        std::tie(i, parent[i]) = {parent[i], u};
                }
            }
        };
        dfs(0);
        for (int i = 0; i < n; ++i)
            e[i].clear();
        for (int i = 1; i < n; ++i)
            e[parent[i]].push_back(i);
        std::vector<Node *> root(n);
        std::function<Node *(int, int, int)> insert = [&](int l, int r, int v) {
            if (r - l == 1)
                return new Node(nullptr, nullptr, 0, 1);
            int m = (l + r) / 2;
            if (v < m) {
                return new Node(insert(l, m, v), nullptr, 0, 1);
            } else {
                return new Node(nullptr, insert(m, r, v), 0, 1);
            }
        };
        for (int i = 0; i < n; ++i)
            root[i] = insert(0, values.size(), a[i]);
        std::function<Node *(Node *, Node *)> merge = [&](Node *p, Node *q) {
            if (p == nullptr)
                return q;
            if (q == nullptr)
                return p;
            if (p -> lc == nullptr && p -> rc == nullptr) {
                int c = (p -> cnt[1] + q -> cnt[1]) % 2;
                return new Node(nullptr, nullptr, c == 0, c == 1);
            }
            Node *r = new Node(merge(p -> lc, q -> lc), merge(p -> rc, q -> rc));
            if (r -> lc != nullptr) {
                r -> cnt[0] += r -> lc -> cnt[0];
                r -> cnt[1] += r -> lc -> cnt[1];
            }
            if (r -> rc != nullptr) {
                r -> cnt[0] += r -> rc -> cnt[0];
                r -> cnt[1] += r -> rc -> cnt[1];
            }
            return r;
        };
        std::function<void(int)> dfs1 = [&](int u) {
            for (auto v : e[u]) {
                dfs1(v);
                root[u] = merge(root[u], root[v]);
            }
        };
        dfs1(0);
        std::function<int(Node *, int, int, int, int)> query = [&](Node *p, int l, int r, int b, int v) {
            if (l >= b || p == nullptr)
                return 0;
            if (r <= b)
                return p -> cnt[v];
            int m = (l + r) / 2;
            return query(p -> lc, l, m, b, v) + query(p -> rc, m, r, b, v);
        };
        int q;
        std::cin >> q;
        while (q--) {
            int v, u, b;
            std::cin >> v >> u >> b;
            --u;
            b = std::upper_bound(values.begin(), values.end(), b) - values.begin();
            std::cout << query(root[u], 0, values.size(), b, v) << "\n";
        }
        return 0;
    }
    
    
    • 1

    信息

    ID
    2253
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者