求树上k级祖先

方法1:类似 LCA,每次倍增地往上跳即可。

Code:

int fa[N][21],dep[N];
void dfs_lca(int u,int father){
    dep[u]=dep[father]+1;
    fa[u][0]=father;
    for(int i=1;(1<<i)<=dep[u];i++)
        fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int i=h[u];i!=-1;i=pre[i]){
        int j=to[i];
        if(j!=father){
             dfs_lca(j,u);
        }
    }
}
int  get_fa(int u,int k){
    int temp=dep[u]-k;
    for(int i=20;i>=0;i--)
        if(dep[fa[u][i]]>=temp)
            u=fa[u][i];
    return u;
}

方法2:长链剖分,每一个重链的顶端存下该链中的点(按深度有序存储)。然后 \(u\) 先跳到 \(u\) 的最远的 \(2^i<k\) 级祖先,这个是 \(O(1)\)。在这个祖先 \(u'\) 上继续跳 \(k-2^i\) 次,这一次跳就直接用其顶端存贮的信息来 \(O(1)\) 找。所以预处理时间复杂度为 \(O(n\log n)\),查询时间复杂度为 \(O(1)\)。有一些证明还需看链接。

posted @ 2024-02-20 16:11  bwartist  阅读(21)  评论(0)    收藏  举报