关于树上k级祖先

Posted 佐世保镇守府

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于树上k级祖先相关的知识,希望对你有一定的参考价值。

关于 \\(Level\\ Ancestor\\) 问题(树上 \\(k\\) 级祖先)的 \\(\\infty\\) 种求法:

\\(\\large\\texttt{Warning:}\\) 此篇博客其实是对 \\(Luogu\\ P5903\\) 题解区中一些方法的汇总梳理,并不是本人原创!!!

  • 树上倍增法:

    主要思路:通过倍增的思想,存下 \\(x\\)\\(2^i\\) 级祖先,在查询时将 \\(k\\) 进行二进制分解,分解为 \\(\\displaystyle\\sum^t_{i=1}2^{a_t}\\) 次方的形式,再每次向上跳 \\(2^{a_t}\\) 步,跳完 \\(t\\) 次后就得到了 \\(x\\)\\(k\\) 级祖先。

    时间复杂度:\\(\\cal{O((n+q)\\log_2n)}\\)

    空间复杂度:\\(\\cal{O(n\\log_2n)}\\)

  • 轻重链剖分法:

    主要思路:进行轻重链剖分,在查询时判断当前点 \\(x\\) 所在的重链顶点是否在其 \\(k\\) 级祖先上放。若不在其上方,则将 \\(x\\) 跳至链顶的父亲节点,并让 \\(k\\) 减去这一段的长度,并继续处理。否则则利用求出的 \\(\\texttt{dfs}\\) 序直接计算。

    时间复杂度:\\(\\cal{O(n-q\\log_2n)}\\)

    空间复杂度:\\(\\cal{O(n)}\\)

  • 轻重链剖分法 + 树上倍增法:

    主要思路:在轻重链剖分法的基础上,利用倍增预先处理出向上跳 \\(2^i\\) 次能到达的节点,就可以优化时间复杂度了。

    时间复杂度:\\(\\cal{O(n\\log_2\\log_2 n - q\\log_2\\log_2 n)}\\)

    空间复杂度:\\(\\cal{O(n\\log_2\\log_2 n)}\\)

  • 长链剖分(咕咕咕)

咕咕咕

[题解/模板]luogu_P3942_(树上覆盖问题

抄题解

把点按深度排序,用near数组记录到每个点最近的关键点的距离,每次取出一个点更新一下near数组,如果不能被覆盖就在它的k级祖先建立关键点,并更新所有k级祖先的k级祖先的near数组

#include<bits/stdc++.h>
using namespace std;
const int maxn=100009;
int n,k,t,ans;
struct edge
    int v,nxt;
e[maxn<<1];
int head[maxn],cnt;
inline void add(int u,int v)
    e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;

struct node
    int dp,id;
    bool operator <(const node&t)const
        return dp>t.dp;
    
p[maxn];
int fa[maxn],nr[maxn];
void pre(int x,int f)
    p[x].dp=p[f].dp+1;fa[x]=f;
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].v==f)continue;
        pre(e[i].v,x);
    

int main()
    scanf("%d%d%d",&n,&k,&t);
    for(int i=0;i<=n;i++)
        nr[i]=maxn;p[i].id=i;
    
    for(int i=1,u,v;i<n;i++)
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    
    pre(1,0);
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++)
        int x=p[i].id,y=x;
        for(int j=1;j<=k;j++)
            nr[x]=min(nr[x],nr[fa[y]]+j),y=fa[y];
        
        if(nr[x]>k)
            nr[y]=0;ans++;
            for(int j=1;j<=k;j++)
                nr[fa[y]]=min(nr[fa[y]],j);y=fa[y];
            
        
    
    printf("%d",ans);

 

以上是关于关于树上k级祖先的主要内容,如果未能解决你的问题,请参考以下文章

luogu P5384 [Cnoi2019]雪松果树

长链剖分 解 k级祖先问题

模板K级祖先(长链剖分)

关于lca

树,LCA,最近公共祖先,倍增

树上倍增求LCA