关于树上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级祖先的主要内容,如果未能解决你的问题,请参考以下文章