题意:给出一颗树。有N个询问,每个询问有两个节点,判断前面的节点是否是后面节点的祖先。
思路:首先要注意到题目中最后树总节点的个数上限为20000000,而对时限是3s,所以算法的复杂度基本上确定为线性。
起初想的是用离线的Tarjan的LCA算法,直接求出两点的LCA,判断LCA是否和前面一个节点相等。然后RE了。最后仔细考虑,觉得应该是递归爆栈了,转换了写人工栈,时间变成了TLE,说明这个算法的复杂度还是比较高的。
首先我们要知道,这道题是没有让求出明确的公共祖先的点,所以我们求出了明确的点,相当于做了多余的东西。
正解是通过一遍DFS,得到每个节点的第一次访问的时间戳pre[u]和退出访问的时间戳post[u]。
在《算法导论》中,对于深度优先遍历树,有一个括号定理:对于u,v,两点,u是v的祖先,当且仅当,pre[u] < pre[v] 且post[u] > post[v](取不取等号要看题目中的定义)。
注意:1.这道题对祖先的定义而言,对于上面的括号定理,是不能加等号的,即自己不能是自己的祖先。
2.不能把图建立后,再用DFS求解,否则会超时。
代码如下:
#include <cstdio>
#include <algorithm>
#include &