树链剖分

Fri Apr 11 2025 09:15:58 GMT+0800


算法目的

维护静态树上的路径信息

算法流程

分两次DFS预处理出以下关键值:

DFS 含义 获得方式
1 father[x] x在树中的父亲 在dfs传参中获得
1 dep[x] x在树中的深度 在dfs传参中获得
1 size[x] x为根的子树大小 在dfs传递归中获得
1 son[x] x的重儿子编号 在dfs传递归中获得
2 top[x] x所在的重路径的顶部结点编号 top[重儿子]=top[自己]
top[轻儿子]=轻儿子
2 seg[x] x在线段树中的位置 按照先访问重儿子的顺序先序遍历树,使得每条重链上的节点在线段树上保持相邻
2 rev[y] y在树中的结点编号 这个简单

线段树的建树和查询的实现就只需按一般的做法

树链的查询

void ask (int x, int y)
{
    int fx = top[x],fy = top[y];
    while(fx != fy)							//直到两个点在同一条重链上
    {
        if(dep[fx] < dep[fy]) 				//选择深度大的往上跳
            swap(x, y),swap(fx, fy);
        query(1, 1, seg[0], seg[fx], seg[x]);	
        x = father[fx]; fx=top[x];
    }
    if(dep[x] > dep[y]) 					//先序遍历导致:在同一棵子树上深度大的点在线段树中的位置靠后
        swap(x, y);
    query(1, 1, seg[0], seg[x], seg[y])		//而seg[x]<=seg[y]故dep[x]<=dep[y]
}