应用DFS序非常好的一道题目
首先考虑暴力如何做,我们先考虑删除的点\(a\)在\(x\)下方,那么就相当于移除\(a\)的子树,由于与子树有关,所以可以想到DFS序
设\(in[a]\)表示DFS序中\(a\)第一次出现的位置,\(out[a]\)表示DFS序中\(a\)第二次出现的位置
当\(x\)固定的时候,如果删除的\(a\)是\(x\)的孩子,那么就相当于DFS序中\([in[a],out[a]]\)的点不可以再访问;如果\(a\)是\(x\)的祖先,设\(nxt[a]\)表示\(a\)到\(x\)的路径中\(a\)的下一个节点,那么就相当于DFS序中\([1,in[nxt[a]]-1]\)和\([out[nxt[a]]+1,n<<1]\)的点不能再访问。我们对每一个\(a\)都讨论这些序列,那么最后就能得出能访问的节点
设\(f[i]\)表示当访问到\(x\)的时候,DFS序中下标\(i\)所代表的节点到\(x\)的距离,由于不可能开\(n\)个\(f[n<<1]\),所以我们考虑实时更新
当即将从\(x\)访问其儿子\(u\)时,假设我们已经更新好了\(x\)的\(f\)
那么对于一个点\(a\),如果\(a\)是\(u\)的孩子,那么\(a\)到\(u\)的距离相当于\(a\)到\(x\)的距离减一;否则相当于加一。这个操作就可以用线段树完成
我们维护好了\(f\)后,假设已经求出仍然能够访问的节点,就利用线段树查询区间最大值就好了
还有一个问题,如果快速求出\(nxt\)数组?其实我们没必要像可持久化那么做,想一下dfs的过程,当dfs到\(x\)这个节点的时候,系统栈里面存储的是从根节点到\(x\)的路径上所有的节点(即\(x\)的所有祖先),如果我们每次在\(x\)即将访问其儿子\(u\)之前,令\(nxt[x]=u\),就可以维护\(nxt\)数组了,这个想法真的是非常妙
注意代码里面,结构体中开一个vector是需要手动clear的
标签:nxt,序中,Tree,DFS,访问,Queries,节点,out From: https://www.cnblogs.com/dingxingdi/p/18044751