Lca树链剖分法

来源:互联网 发布:stl源码是什么 编辑:程序博客网 时间:2024/05/18 02:51

树链剖分各数组的作用:
son[]:最重的儿子节点,即节点最多的那个
bulk[]:所有儿子节点的总和(包括儿子的儿子)
dep[]:该节点的深度
ft[]:该节点的父亲
top[]:链的最上方的节点

首先Dfs预处理出前面的四个数组。
然后第二个Dfs进行剖分,预处理出最后一个数组。

例子:
这里写图片描述
此时son[1]=3(因为bulk[3]=6>bulk[2]=5),son[3]=10,son[4]=5,以此类推。

然后剖分之后相当于变成了
这里写图片描述
此时top[10]=1,top[7]=7,top[8]=9,以此类推

接下来就是进行Lca,假设c=lca(a,b),首先,当a,b在同一条重链中时,c=min(dep[a],dep[b]),当a,b不在同一条重链中时,画图易知c一定是划分轻重链的的那个分支点,比如图中的1,3,4。假设我们现在要求lca(7,8),那么lca(7,8)一定是某条直到7,8在同一条重链时的分支点,所以不断地把7,8向上合并到重链中,直到他们在同一条重链中。

现在进行模拟,先看看代码中的Lca,方便理解。令x=7,y=8,因为dep[top[x]]>dep[top[y]](top[x]=7,top[y]=9),所以更新x=4,发现top[x](top[x]=2),top[y](top[y]=9)不在一条重链中,继续更新,此时dep[top[y]]大,更新y=3,因为dep[top[x]]大,更新x=1,发现他们已经在同一条重链中,那么深度小的即为lca(7,8)

附模板:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 1000;struct Edge{    int v, next;    Edge(int v=0,int next=0):v(v),next(next){}}edge[MAXN];int head[MAXN], edgenum;//邻接表int son[MAXN], bulk[MAXN], dep[MAXN], ft[MAXN], top[MAXN];void toInit(){    memset(head, -1, sizeof(head));    edgenum = 0;}void toAdd(int u,int v){    edge[edgenum] = Edge(v, head[u]);    head[u] = edgenum++;}void toDfs1(int u,int f,int tier){    son[u] = 0;dep[u] = tier;ft[u] = f;bulk[u] = 1;    for (int i = head[u];i != -1;i = edge[i].next)    {        int v = edge[i].v;        if (v == f) continue;        toDfs1(v, u, tier + 1);        bulk[u] += bulk[v];        if (bulk[v] > bulk[son[u]])//son[]更新为重儿子            son[u] = v;    }}void toDfs2(int u,int f,int rt){    top[u] = rt;    for (int i = head[u];i != -1;i = edge[i].next)    {        int v = edge[i].v;        if (v == f) continue;        if (v == son[u])//链剖分            toDfs2(v, u, rt);//重链top继承父亲的top        else            toDfs2(v, u, v);//轻链top为自身    }}int toLca(int x,int y){    while (top[x] != top[y])    {        if (dep[top[x]] < dep[top[y]])            swap(x, y);//使深度大的始终为x        x = ft[top[x]];    }    return dep[x] < dep[y] ? x : y;}int main(){    return 0;}
原创粉丝点击