[题解] CF1328E Tree Queries
CF1328E Tree Queries
题意
给定一棵以
现在有
思路
我们首先可以给出一个结论:如果节点
- 当点
正好在这条链上时,那么其父亲节点正好位于根节点与 的路径上,也就是位于链上; - 当点
与链的距离为 时,由于该链的起点为根节点,那么意味着这条链经过 的父亲节点,但是没有到达 ,否则由于树上路径唯一,链不可能经过 的儿子节点。
综上,我们可以将问题转化为:给定的节点的父亲节点是否在一条以根节点为起点的树链上。
对于这个问题,我们可以先对所有给定节点的父亲节点按照深度排序。因为对于任意一个节点,其一定与根节点是在一条链上的,因此我们要验证的是,所有节点之间是否在一条链上。
我们考虑为什么任意一个节点一定与根节点是在同一条链上的问题。对于任意一个节点,其一定是在根节点的子树之内,树上两点之间有且仅有一条简单路径,因此该子问题得到验证。
那么我们想要知道这
综上所述,我们可以先对整棵树计算一次深度、 dfs
序、子树节点个数后,对于每次询问,我们将节点转化为其父亲节点,并按照深度从小到大排序,最后验证深度大的节点是否位于前一个深度小的子树,即可。
实现
#include <iostream> #include <vector> #include <algorithm> int main() { std::cin.tie(nullptr)->sync_with_stdio(false); int n, q; std::cin >> n >> q; std::vector adj(n, std::vector<int>{}); for (int i = 0; i < n - 1; i ++) { int u, v; std::cin >> u >> v; u --; v --; adj[u].emplace_back(v); adj[v].emplace_back(u); } std::vector<int> dep(n, -1), dfn(dep), siz(dep), fa(dep); auto dfs = [&, stamp{-1}](auto &self, int from, int come) mutable -> void { dfn[from] = ++ stamp; siz[from] = 1; fa[from] = come; for (auto to : adj[from]) { if (dep[to] == -1) { dep[to] = dep[from] + 1; self(self, to, from); siz[from] += siz[to]; } } }; dep[0] = 0; dfs(dfs, 0, 0); for (int t = 0; t < q; t ++) { int m; std::cin >> m; std::vector<int> ls(m); for (auto &item : ls) { std::cin >> item; item --; item = fa[item]; } std::ranges::sort(ls, std::less{}, [&](auto x) { return dep[x]; }); bool ok = true; for (int i = 1; i < m && ok; i ++) { int pre = ls[i - 1], now = ls[i]; ok &= (dfn[pre] <= dfn[now] && dfn[now] <= dfn[pre] + siz[pre] - 1); }; if (ok) { std::cout << "YES\n"; } else { std::cout << "NO\n"; } } }
本文作者:FlandreScarlet
本文链接:https://www.cnblogs.com/FlandreScarlet/p/17684222.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步