DFS Checker (Hard Version)§
对于所有操作显然不能暴力判断是否合法,往优化暴力的角度上去思考也是不可取的。
其实可以想一下当前序列满足
DFS序列的充要条件。我们可以先寻找一些共性。
对于当前序列,只取相邻的两个元素,若当前序列是
DFS序列,这两个元素会有什么特点?显然,第一个特点是后一个元素一定不是前一个元素的祖先,这不需要怎么解释,
DFS的特性罢了。第二个特点是后一个元素的父亲一定是前一个元素的祖先(也可能后一个元素的父亲就是前一个元素)。
这里就需要大胆猜想,假如所有相邻情况都满足以上特点,这个序列一定是
DFS序列。题目的交换操作影响的相邻情况并不多,也就是说其它没影响到的情况的正确性可以继承下去。
我们可以维护满足情况的数量,如果所有情况都满足即数量为
n - 1当前序列合法。判断祖先关系可以手撸
LCA,也可以预处理DFN序来判断。下方代码是偷的HLD板子。#include <bits/stdc++.h> struct HLD { int n; std::vector<int> siz, top, dep, parent, in, out, seq; std::vector<std::vector<int>> adj; int cur; HLD() {} HLD(int n) { init(n); } void init(int n) { this->n = n; siz.resize(n); top.resize(n); dep.resize(n); parent.resize(n); in.resize(n); out.resize(n); seq.resize(n); cur = 0; adj.assign(n, {}); } void addEdge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void work(int root = 0) { top[root] = root; dep[root] = 0; parent[root] = -1; dfs1(root); dfs2(root); } void dfs1(int u) { if (parent[u] != -1) { adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u])); } siz[u] = 1; for (auto &v : adj[u]) { parent[v] = u; dep[v] = dep[u] + 1; dfs1(v); siz[u] += siz[v]; if (siz[v] > siz[adj[u][0]]) { std::swap(v, adj[u][0]); } } } void dfs2(int u) { in[u] = cur++; seq[in[u]] = u; for (auto v : adj[u]) { top[v] = v == adj[u][0] ? top[u] : v; dfs2(v); } out[u] = cur; } int lca(int u, int v) { while (top[u] != top[v]) { if (dep[top[u]] > dep[top[v]]) { u = parent[top[u]]; } else { v = parent[top[v]]; } } return dep[u] < dep[v] ? u : v; } int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; } int jump(int u, int k) { if (dep[u] < k) { return -1; } int d = dep[u] - k; while (dep[top[u]] > d) { u = parent[top[u]]; } return seq[in[u] - dep[u] + d]; } bool isAncester(int u, int v) { return in[u] <= in[v] && in[v] < out[u]; } int rootedParent(int u, int v) { std::swap(u, v); if (u == v) { return u; } if (!isAncester(u, v)) { return parent[u]; } auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) { return in[x] < in[y]; }) - 1; return *it; } int rootedSize(int u, int v) { if (u == v) { return n; } if (!isAncester(v, u)) { return siz[v]; } return n - siz[rootedParent(u, v)]; } int rootedLca(int a, int b, int c) { return lca(a, b) ^ lca(b, c) ^ lca(c, a); } }; void solve() { int n, q; std::cin >> n >> q; HLD t(n); std::vector<int> a(n), p(n); for (int i = 1; i < n; i++) { std::cin >> a[i]; --a[i]; t.addEdge(a[i], i); } t.work(); for (auto &it : p) { std::cin >> it; --it; } int cnt = 0; std::vector<bool> good(n); auto check = [&](int u) -> void { if (u < 1 || u >= n) { return; } cnt -= good[u]; good[u] = (!t.isAncester(p[u], p[u - 1])) && t.isAncester(a[p[u]], p[u - 1]); cnt += good[u]; }; for (int i = 1; i < n; i++) { check(i); } while (q--) { int x, y; std::cin >> x >> y; --x, --y; std::swap(p[x], p[y]); check(x); check(x + 1); check(y); check(y + 1); if (cnt == n - 1) { std::cout << "YES\n"; } else { std::cout << "NO\n"; } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; std::cin >> t; while (t--) { solve(); } return 0; }