树链剖分

多日前的博客,放在草稿箱快发霉了,今日来填坑!!!

老早前听了一位大佬的难题选讲(难车选开)介绍了一下树链剖分,感觉很妙妙,恰好大佬降得蛮详细的,不花多少时间就理解了

在这里就来介绍一下树链剖分,巩固一下记忆。

还记得最初听一群大佬在以前难题选讲的时候,就用树链剖分来讲题,结果必然是直接全程懵逼,那时我旁边的宋爷就发誓要学这玩意儿,结果一起看博客又有点懵,没坚持下来。倒是宋爷过了一段时间继续重拾树链剖分,250+行代码强行写出,弄得我心里痒痒的,于是就学呗。。。。

【树链剖分???】

树链剖分能实现什么呢,这是我第一个想到的问题,想必初学者也疑问过,下面列举一下模板能干什么:

 

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

操作5: 格式: x y 表示求x和y的LCA

【基础姿势】

 

1、重儿子:每个节点的子树最大的子节点(如图中标没有红点的节点)

2、 轻儿子:除去重儿子的节点

3、重链:以每个轻儿子为起点到重儿子,路径上除起点外都是重儿子(也可以是单个轻儿子  如1—>4—>9—>13—>14)

4、轻链:除去重链以外的路径

5、链顶:每条链的起点,一定是轻儿子

6、树链剖分搜索顺序:优先深搜一个节点的重儿子,再搜其他儿子

储存结构

siz[v]  以v为根节点的子树的大小

fa[v]  节点v的父节点

son[v]  节点v的重儿子

top[v]  节点v所在链的链顶

dep[v]  节点v的深度

【建树操作】

1、dfs( )

第一次dfs我们是按dfs序来操作,更新fa[v] dep[v] siz[v] son[v]

 1 int dfs(int now,int ff,int deep)
 2 {
 3     fa[now]=ff,dep[now]=deep,siz[now]=1;
 4     int ms=-1,maxx=-1;
 5     for(int i=head[now];i!=0;i=edge[i].next)
 6     {
 7         if(edge[i].to!=ff)
 8         {
 9             int gg=dfs(edge[i].to,now,deep+1);
10             if(maxx<gg)
11             { maxx=gg,ms=edge[i].to; }
12             siz[now]+=gg;
13         }
14     }
15     if(ms==-1) son[now]=now;
16     else son[now]=ms;
17     return siz[now];
18 }

1、dfs2( )

第二次dfs我们是按树链剖分的顺序来操作,更新top[v]

 1 void dfs2(int now,int tt)
 2 {
 3     cnt++,ord[cnt]=now,idx[now]=cnt,top[now]=tt;
 4     if(son[now]==now) return;
 5     dfs2(son[now],tt);
 6     for(int i=head[now];i!=0;i=edge[i].next)
 7     {
 8         if(edge[i].to!=fa[now]&&edge[i].to!=son[now])
 9             dfs2(edge[i].to,edge[i].to);
10     }
11 }

接下来我们可以开始学习基本操作了(其实觉得LCA更简单,更贴切模板)

求LCA:点我查看

树链剖分模板:点我查看

posted @ 2018-05-15 23:40  genius777  阅读(187)  评论(0编辑  收藏  举报