树链剖分

树链剖分

前言:虽然noip基本不考,但我觉得还是多少学一点吧


问题模型

对于树上的某条路径,进行一系列操作(类似线段树上的操作)


实现原理

恰如其名,将树剖分成一段又一段的区间(树链),便于我们进行线段树的操作(树上的线段树操作)。将树分为重链和轻链,重链的dfs序(与其他dfs序不同,树剖的dfs序会优先落在重链上)多为一段连续的区间。因此当解决两点间路径上的查询和修改问题时,可以用类似于LCA(其实区别较大,LCA是通过倍增来跳,而树剖是通过重链来跳)的方法,将两点之间的路径剖分成多条首尾相连的树链,每条树链上的点所在区间是连续的,进而进行线段树的操作。(关于重链,轻链的定义请自行查询)


代码实现

进行两遍dfs,第一遍储存size[],father[],son[](重儿子),dep[]

第二遍储存top[](所在重路径的顶部节点),seg[](在线段树中的位置),rev[](rev[seg[x]]=x)

void dfs1(int u,int father)
{
    ssize[u]=1;
    dep[u]=dep[father]+1;
    fa[u]=father;
    for(int i=fir[u];i;i=nxt[i])
    {
        int v=vv[i];
        if(v==father)continue;
        dfs1(v,u);
        ssize[u]+=ssize[v];
        if(ssize[v]>ssize[son[u]])son[u]=v;
    }
}
/*
void dfs2(int u,int father)
{
    if(son[u])
    {
        seg[son[u]]=++seg[0];
        rev[seg[son[u]]]=son[u];
        top[son[u]]=top[u];
        dfs2(son[u],u);
    }
    for(int i=fir[u];i;i=nxt[i])
    {
        int v=vv[i];
        if(!top[v])
        {
            seg[v]=++seg[0];
            rev[seg[v]]=v;
            top[v]=v;
            dfs2(v,u);
        }
    }
}*/

**\(update\)\(11\)\(15\)

最近了解到\(dfs2\)的第二种写法,不但码量少,而且可以不用在\(main\)函数里初始化\(root\)\(dfs\)

void dfs2(int u, int tp)
{
    seg[u] = ++seg[0]; rev[seg[0]] = u; top[u] = tp;
    if(son[u] != 0) dfs(son[u], tp);
    for(int i = fir[u]; i; i = nxt[i])
    {
        int v = vv[i];
        if(v == fa[u] || v == son[u]) continue;
        dfs2(v, v);
    }
}

**

当查询两点之间的路径时,通过每次top[]较深的点往上跳,当跳到同一条重链上时,深度较浅的一点即为两点的LCA,再将两点的路径转化为多条重链(跳跃的过程),分别进行区间查询。

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]);
}

例题

[Noi2015]软件包管理器

解析:虽然是NOI的题,但却是一道Day1 T2的除了题意比较冗长外的极水的树链剖分裸题。安装软件包就是将根节点到x节点的路径上所有值变为1,卸载软件包就是将x节点和它所有子树节点的值变为0,而x和它的子树节点在树链剖分中恰好是一段连续的区间[seg[x],seg[x]+size[x]-1],然后直接树链剖分做就可以了。

posted @ 2019-07-21 12:10  Akaina  阅读(171)  评论(0编辑  收藏  举报