一只兔子对于树链剖分的理解

原创 2016年06月01日 16:30:03

树链剖分是做甚的?

某个早上,一只兔子沿一条不规则的曲线冲过来,问了另一只兔子这个问题。
这只兔子当场开始转圈(这是它的一种癖好)。
兔子新的一天开始了…

0

树链剖分?什么鬼?
不太懂的小兔子向老兔子(场外观众)求援了。
“咳咳,顾名思义,树链剖分嘛,就是把树剖分成链……”
“这不废话吗?”
“……剖分成若干条链,然后把每条链扔进数据结构里维护……”
“等等树链剖分是干吗的?”
“……以解决如把一棵树上同时增减节点x到节点y的权值之类的问题……”
“……”
(太给力了,你的回答完美的解决了我的问题?)(某熊乱入,惊散兔子)

1

树链剖分有俩个东东
重边 轻边
重边:比较重的那边
轻边:比较轻的那边
嗯,老兔子喝了点伏特加(然而并不是广告)(推)
size(x):以节点x为根的子树的节点个数
重边:节点x与其有最大的size值的那个儿子之间的边
轻边:除了重边外的边全是轻边
“为什么要这样做?”
(老兔子爬起)“Just for fun.啊,不是不是为为为为了使链的数目尽量少,省事。”(又自己摔倒)
“好像有道理…”

于是就有了这两个性质
(1)轻边(u,v)中,size(v)<=size(u)/2
(2)从根到某一点的路径上,轻边、重边条数不超过log n。

2

重边轻边好分,不过怎么连成链呢?
我们把重边连起来:从根节点开始,沿着重边往下找,拉成重链,不在这条重链上?那就从这个节点再往下拉一条。
Talking is easy.Show me the…picture.
树链剖分图

3

以下是一些数组

  • 之前的size[]数组
  • 为了区分重边轻边,我们需要ch[]保存重儿子
  • 当然有儿子就有爹——fa[]数组
  • 为了区分边所属的链,我们需要top[]数组,保存该节点的所在链的顶端节点
  • 为了防止搞混编号,我们需要tid[]数组,保存树中每个节点剖分后的新编号;zrank[]数组,保存当前节点在线段树中的位置
  • 嗯我们还需要一个记录深度的dep[]数组,原因…就不用说了…

4

老兔子:”让我翻出70年的雪碧,啊不是15年的代码”

int point[MAX_N],size[MAX_N],top[MAX_N],ch[MAX_N];
int deep[MAX_N],tid[MAX_N],zrank[MAX_N],fa[MAX_N];
int head[MAX_N],to[2*MAX_N],znext[2*MAX_N],edge;//链式前向星

void zinit() {
    memset(head,-1,sizeof(head));
    memset(ch,-1,sizeof(ch));
    num=0;edge=0;
}

void add_edge(int u,int v) {
    to[edge]=v,znext[edge]=head[u],head[u]=edge++;
    to[edge]=u,znext[edge]=head[v],head[v]=edge++;
}

void dfs1(int u,int pa,int d) {
    deep[u]=d;
    fa[u]=pa;
    size[u]=1;
    for(int i=head[u];~i;i=znext[i]) {
        int v=to[i];
        if(v!=pa) {
            dfs1(v,u,d+1);
            size[u]+=size[v];
            if(ch[u]==-1||size[v]>size[ch[u]])
                ch[u]=v;
        }
    }
}

void dfs2(int u,int tp) {
    top[u]=tp;
    tid[u]=++num;
    zrank[tid[u]]=u;
    if(ch[u]==-1) return;
    dfs2(ch[u],tp);
    for(int i=head[u];~i;i=znext[i]) {
        int v=to[i];
        if(v!=ch[u]&&v!=fa[u])
            dfs2(v,v);
    }
}
版权声明:咳,博主原创,需博主许可方能转载。

树链剖分-入门题目

Query on a tree 题目链接: http://vjudge.net/problem/SPOJ-QTREE 题目大致意思就是: 给你一棵树,有连个操作:       ● 第一个...
  • WR_technology
  • WR_technology
  • 2016年11月12日 16:37
  • 679

树链剖分入门讲解

“在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分。树链,就是树上的路径。剖分,就是把路径分类为重...
  • bobodem
  • bobodem
  • 2016年08月26日 17:22
  • 1536

倍增/树链剖分解决LCA问题

已知一棵树,给出u,v两点,求它们的最近公共祖先,这就是LCA问题(Least Common Ancestors)。 如上图,LCA(15,7)=6,LCA(11,3)=10,LCA(1...
  • lian233
  • lian233
  • 2017年02月27日 20:52
  • 185

树链剖分教程 & bzoj 1036 [ZJOI2008] 树的统计 Count 题解

【原题】 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4465  Solved: 1858...
  • u013724185
  • u013724185
  • 2014年04月28日 22:27
  • 5598

HDU3966(树链剖分)

题目:Aragorn's Story   题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的...
  • ACdreamers
  • ACdreamers
  • 2013年08月30日 14:15
  • 7226

树链剖分小结及题目

我们经常会遇到这样一类题目:给出一棵树,询问树上u,v两点路径间的最值,合值,更新u,v路径上的点权或边权,或者区间更新etc,此时如果单纯的用线段树或者树状数组去搞,很明显问题不能够得到完美解决,此...
  • Forever_wjs
  • Forever_wjs
  • 2016年08月04日 10:28
  • 2028

树链剖分个人题目总结

首先,想要学树链剖分基础的朋友们很抱歉请换篇博客看,,,这是个题目总结 ////////////////////////////////// 本蒟蒻求不被大佬嘲讽。。。。 //////////////...
  • JetRichardLee1
  • JetRichardLee1
  • 2017年03月17日 18:15
  • 268

树链剖分详解及模板

这几天学习了一下树链剖分,顺便写一下我的理解、 早上看了一下别人的讲解,云里雾里,终于算是搞懂了、 树链剖分是解决在树上进行插点问线,插线问点等一系列树上的问题 假如现在给你一棵树,...
  • y990041769
  • y990041769
  • 2014年10月21日 17:40
  • 21060

POJ 2763 树链剖分

点击打开链接 题意:给一个树,然后树上的边的边权,然后两个操作,一个是询问u到v的路上权值和,一个是将第几条边的权值修改 思路:与SPOJ 375 的那道题目很像,都是边上的权值,然后维护一个线段...
  • Dan__ge
  • Dan__ge
  • 2016年07月11日 14:14
  • 1050

洛谷 P3384 【模板】树链剖分

树链剖分
  • Rlt1296
  • Rlt1296
  • 2017年04月14日 21:23
  • 370
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一只兔子对于树链剖分的理解
举报原因:
原因补充:

(最多只允许输入30个字)