1 条题解
-
0
自动搬运
来自洛谷,原作者为

jiangly
这个家伙很菜,什么也没有留下搬运于
2025-08-24 21:46:11,当前版本为作者最后更新于2020-04-12 18:24:00,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题意
给定一个 个点 条边的仙人掌 (, ),定义 的子仙人掌为去掉 到 的所有简单路径经过的街道后 所在的连通块。每个点有点权, () 次询问一个点的子仙人掌中出现次数为奇数/偶数的点权个数。
题解
进行一遍 dfs, 对于每个环,删掉其中的所有边并从其中 dfs 序最小的点向环上其他所有点连边。容易发现,进行这样的操作后原图变成了一棵树,且这个树上 的子树所包含的点与原图中 的子仙人掌所包含的点相同。问题转化为了子树询问,因此线段树合并即可。
时间复杂度:。
代码
#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
- 上传者