P3180 [HAOI2016]地图 题解
题意
给定一个
题解
进行一遍 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;
}