Tree Queries

应用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的

还有一个奇怪的看不懂的解法

posted @ 2024-02-29 16:51  最爱丁珰  阅读(3)  评论(0编辑  收藏  举报