树链剖分边权版

博客围绕树链剖分边权版展开,但具体内容缺失。树链剖分边权版是信息技术领域算法相关内容,可用于解决树上路径问题等。
int tol,head[maxn];
struct edge
{
    int to,next;
}es[maxm];
void addedge( int u , int v )
{
    es[tol].to = v;
    es[tol].next = head[u];
    head[u] = tol++;
}
int top[maxn],fa[maxn],dep[maxn],sizes[maxn],tid[maxn],rk[maxn],wson[maxn],num;
void init()
{
    tol = 0;
    memset ( head , -1 , sizeof(head) );
    num = 0;
    memset ( wson , -1 , sizeof(wson) );
}
void dfs1( int u , int f , int d )
{
    dep[u] = d,fa[u] = f,sizes[u] = 1;
    for ( int i=head[u] ; i!=-1 ; i=es[i].next )
    {
        int v = es[i].to;
        if ( v!=f )
        {
            dfs1 ( v , u , d+1 );
            sizes[u] += sizes[v];
            if ( wson[u]==-1||sizes[v]>sizes[wson[u]] )
                wson[u] = v;
        }
    }
}
void dfs2( int u , int tp )
{
    top[u] = tp,tid[u] = ++num,rk[tid[u]] = u;
    if ( wson[u]==-1 ) return;
    dfs2( wson[u] , tp );
    for ( int i=head[u] ; i!=-1 ; i=es[i].next )
        if ( es[i].to!=fa[u]&&es[i].to!=wson[u] ) dfs2( es[i].to , es[i].to );
}
dfs1( 1 , 0 , 1 );
dfs2( 1 , 1 );
for ( int i=2 ; i<=n ; i++ )
{
    if ( dep[u[i]]<dep[v[i]] ) swap ( u[i] , v[i] );
    val[u[i]] = w[i];
}
void Change( int u , int v )
{
    while ( top[u]!=top[v] )
    {
        if ( dep[top[u]]<dep[top[v]] ) swap ( u , v );
        Update( tid[top[u]] , tid[u] , 2 , n , 1 );
        u = fa[top[u]];
    }
    if ( dep[u]>dep[v] ) swap ( u , v );
    Update( tid[u]+1 , tid[v] , 2 , n , 1 );
}

 

### 树链剖分概念及其实现 树链剖分是一种用于高效处理树上路径查询和修改操作的技术。它通过对树进行分解,使得任意两点之间的路径可以被划分为不超过 \(O(\log n)\) 条连续的重链[^1]。 #### 原理概述 树链剖分的核心思想是将一棵树按照某种方式划分成若干条“链”,并通过这些链来加速对树的操作。具体来说,树链剖分会定义一条从根节点到叶子节点的主要路径(称为重儿子),并将其余子树视为轻儿子。这种划分能够保证任何两个节点间的路径都可以表示为少量的链连接而成。 #### 实现步骤 以下是树链剖分的一般实现流程: 1. **预处理阶段** 需要先完成 DFS 序列化以及计算每个节点的深度、父节点、重儿子等信息。 2. **建立重链** 使用递归来遍历整棵树,在每一步中优先访问当前节点的重儿子,并记录下属于同一条重链的所有节点。 3. **映射关系维护** 将原树上的节点与其对应的重链编号关联起来,便于后续快速定位。 下面给出一段基于 C++ 的简单实现代码示例: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 7; vector<int> adj[MAXN]; int sz[MAXN], heavyChild[MAXN], parentOfHeavyChain[MAXN], chainHead[MAXN], posInBaseArray[MAXN], currentPos, depthOfNode[MAXN]; void dfsSize(int u, int p){ sz[u]=1; heavyChild[u]=-1; for(auto &v : adj[u]){ if(v !=p ){ depthOfNode[v] =depthOfNode[u]+1 ; parentOfHeavyChain[v ]=u ; dfsSize( v , u ); sz[ u ]+=sz[ v ]; if (heavyChild[u]==-1 || sz[v]>sz[heavyChild[u]]) { heavyChild[u]=v; } } } } void decomposeTreeIntoChains(int u,int h){ chainHead[currentPos]=h; posInBaseArray[u]=currentPos++; if(heavyChild[u]!=-1){ decomposeTreeIntoChains(heavyChild[u],h); for(auto &v:adj[u]){ if(v!=parentOfHeavyChain[u] && v!=heavyChild[u]){ decomposeTreeIntoChains(v,v); } } } } ``` 此代码片段展示了如何利用两次DFS分别求解大小数组 `sz[]` 和分配重链头指针的过程。 #### 应用场景 树链剖分广泛应用于各种涉及复杂树结构的问题解决当中,尤其适合以下几种情况: - 路径上的加减乘除运算; - 子树范围内的统计汇总; - LCA最近公共祖先查找等问题; 例如,在动态规划或者图论题目里经常遇到需要频繁询问某棵子树内部的信息总和或是两节点之间边权最大最小值等情况时,采用树链剖分会显著提升效率。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值