【算法复习】 树链剖分

来源:互联网 发布:数据分析师市场需求 编辑:程序博客网 时间:2024/06/03 16:19

NOIP快到了,本蒟蒻太菜了,今天复习一下树链剖分。

暑假学习了一发树链剖分,打了几题模板题之后就没打了。




一些概念(下面代码会用到):

Son[u]:u结点的重儿子

Size[u]:以u为结点的子树的大小

fa[u]:u结点的父亲

top[u]:该重链的链顶

Num[u]:剖分后的结点编号

Deep[u]:u结点的深度

第一步(Dfs1):找到每个节点的重儿子(子树结点数最大的儿子),同时记录每个结点的深度,父亲,子树大小等必要信息

void Dfs1(int u) //找重儿子 {Size[u]=1;for (int i=head[k];i;i=E[i].next){  int v=E[i].to;  if (v==fa[u]) continue;  fa[v]=u; Deep[v]=Deep[v]+1;  Dfs1(v);  Size[u]+=Size[v];  if (Size[v]>Size[Son[u]]) Son[u]=v;}}
第二部(Dfs2): 由重儿子打通每一条重链

void Dfs2(int u,int Top)//打通重链{Num[u]=++Index,top[u]=Top;if (!Son[u]) return;Dfs2(Son[u],Top);for (int i=head[u];i;i=E[i].next){  int v=E[i].to;  if (v==fa[u] || v=Son[u]) continue;  Dfs2(v,v);}}


两个Dfs完了之后,那么一棵树就剖分完成了。(可以手画一棵复杂一点的树理解一下)

然后就会发现一个非常重要的性质:每一条重链上的编号是连续的!!!

接下来就可以用一些其他的数据结构来维护这每一条重链,比如线段树,Splay等等

然而本蒟蒻非常菜,只打过用线段树维护的树链剖分题目


以线段树为例,对于一对结点(u,v),将这两个点不断沿着重链往上爬,边爬边维护重链上的信息,最终这两个点会跳到同一条重链上,这时候在维护一次就好。

void Work(int x,int y){while (top[x]!=top[y])//不在一条重链上 {  if (Deep[x]<Deep[y]) swap(x,y);//先跳深度大的点   Modify(1,1,n,Num[top[x]],Num[x]);//线段树修改操作   x=fa[top[x];//跳到该重链链顶的上方,即下一条重链 }//接下来是处理同一条链上的情况 if (Deep[x]<Deep[y]) swap(x,y);Modify(1,1,n,Num[y],Num[x]);} 



怎么样,树链剖分是不是很简单。(然而去年不知道自己在干什么居然不会学这个东西)

基本上就是模板了,大致就这样吧,本蒟蒻就只会这些了