关于第2题的想法:
因为一定要保含某个标记(节点),所以可以从这个点为根节点出发找最长链。但是这样,由于询问(求某个标记为根的最长链长度)比较多,如果用普通求最长链的话,还要每次都DFS一遍,这样是非常不划算的,因为这样重复获得了一些已经获得的结果。
于是我加一个优化:假设这条最长链一定会经过树根(原来的),那么它的最长链就一定是从它往下找最长和次长,再往上找最长,结果就是把往下的次长与往上的最长取max然后加上往下的最长。
然后这样就可以把第一遍DFS记下的fromroot[]和dpth[]更好的利用。那么我现在去掉最长链一定经过原来的根节点这个假设,那么对于每个树的内部节点,从它开始的最长链(不考虑从询问目标到它)一定是在与它相连的剩下的链中,即若DFS查找的话需要在往它的父亲和其他孩子(除了到这个点时经过的)走然后继续查找。那我要知道的就只是从Target到Now的距离+从Now出发能找到的“最长链”,并对所有的取个max。所以我一定需要Now往它的“所有”孩子的走法能得到的最长链长度,这样就只需要往原树根走了。至于为什么不用记下往父亲走的最长链,在证明这个算法的正确性的时候可以证明。因为假如到了原来的根节点,那么已经获得了关于它的所有链的长度,这在第一遍DFS返回的时候可以获得,然后我处理一下,就需要记录下除了第I个孩子开始的链的最长的从根节点开始的最长链的长度。但是这样有个很严重的问题,空间可能不行。那么我就可以不把这些值记录在根节点上,而是分散到每个孩子上,这样就不需要为每个节点开一个大小不一定适合的数组或用比较慢的stl,也不需要动态内存了。这样我对于每个节点,我需要记下的就不是2个量(最长,次长),而是3个!而这新的量可以在第1遍DFS时算出(离线真是个好东西)。
至于实现嘛,查找的时候只需按照层返回到根就行了,这可能是logN级别时间复杂度。
另外,这样的算法可能还是会出现重复的情况。不过好在题目是没有修改的,也不是强制在线的,我可以做完第一遍DFS后把所有的询问排序一下,按照深度从小到大排序,然后对于排完的队列从前往后正常查找,得到的往上的最长链的值可以利用,减少重复(那我就把这个量记下),之后询问的时候遇到这个节点可以直接利用。
还有,往下的最长链和次长链的长度可以在第一遍DFS的时候算出
备注:本人第一次用md,格式写得很烂,请巨佬们飘过