[Luogu 3398] 仓鼠找sugar
又是 LCA…
前两天死活写不过的一个题今天终于顺手切了。
思路嘛参考了一楼题解。
就是说,对于 a
, b
, c
, d
四个点,
令 x
= LCA(a, b), y
= LCA(c, d),
两条路径有交叉,当且仅当 c
, d
至少一个在 x
的子树下,且 a
, b
至少一个在 y
的子树下。
由于我是 HLD 求的 LCA,第一遍 DFS 时顺手把子树大小求了,后边判断在不在一棵子属下的时候就可以很方便了。
就这样。
#include#include const int MAXN = 100010; int n, q; struct Graph{ struct Edge { int to; Edge *next; Edge(int to, Edge* next): to(to), next(next) {} ~Edge(void) { if(next != NULL) delete next; } }*head[MAXN]; Graph(int n) { std :: fill(head + 1, head + n + 1, (Edge*)NULL); } ~Graph(void) { for(int i = 1; i <= n; ++i) delete head[i]; } void AddEdges(int u, int v) { head[u] = new Edge(v, head[u]); head[v] = new Edge(u, head[v]); }}*G; namespace HLD{ int num; struct Node { int depth, father, son, top, size, DFN; }s[MAXN]; void DFS1(int u, int k) { s[u].depth = k; s[u].size = 1; int v; for(Graph :: Edge *i = G -> head[u]; i != NULL; i = i -> next) if(!s[v = i -> to].size) { DFS1(v, k + 1); s[u].size += s[v].size; s[v].father = u; if(s[v].size > s[s[u].son].size) s[u].son = v; } } void DFS2(int u, int top) { s[u].top = top; s[u].DFN = ++num; if(s[u].son) DFS2(s[u].son, top); int v; for(Graph :: Edge *i = G -> head[u]; i != NULL; i = i -> next) if(!s[v = i -> to].DFN) DFS2(v, v); } void Init(void) { DFS1(1, 1); DFS2(1, 1); } int LCA(int x, int y) { int a, b; while((a = s[x].top) ^ (b = s[y].top)) if(s[a].depth > s[b].depth) x = s[a].father; else y = s[b].father; return s[x].depth < s[y].depth ? x : y; } bool Range(int x, int y) { return s[x].DFN <= s[y].DFN && s[y].DFN < s[x].DFN + s[x].size; } bool Query(int a, int b, int c, int d) { int x = LCA(a, b), y = LCA(c, d); return (Range(x, c) || Range(x, d)) && (Range(y, a) || Range(y, b)); }}int main(void){ scanf("%d %d", &n, &q); G = new Graph(n); for(int i = 1, u, v; i < n; ++i) { scanf("%d %d", &u, &v); G -> AddEdges(u, v); } HLD :: Init(); for(int i = 1, a, b, c, d; i <= q; ++i) { scanf("%d %d %d %d", &a, &b, &c, &d); puts(HLD :: Query(a, b, c, d) ? "Y" : "N"); } return 0; }
谢谢阅读。