zoukankan      html  css  js  c++  java
  • 关于树链剖分

    树链剖分

    树链剖分可以解决树上路径,子树之类的一系列问题。

    下面以[LuoguP3384]为例,讲解关于树链剖分的部分操作。

    主要思想

    树剖通过一种特殊的枚举方法,将树上的路径转化成连续的几段,通过线段树等操作去维护。

    预处理

    树链剖分的主要通过两个dfs求出以下需求的值

    • depth[x]:x的深度

    • fa[x]:x的父节点

    • sum[x]:包括节点x的子树一共有多少个节点

    • heavy_son[x]:x的重儿子

    • top[x]:x所在重链的首部

    • id[x]:x节点在线段树中对应的下标

    下面对于一些量做出解释

    重儿子:x的儿子中sum[x]最大的那个节点

    重链:在树链剖分中,为了将一棵树剖分成连续的线段,通常采用从根节点开始,先访问重儿子,再访问其它儿子的方式,并将访问的时间顺序依次在线段树中将树上节点对应线段树的点1,2,3...n。

    这样操作一条重链上的点所对应的线段树的节点就是连续的(即id[x]是连续的) 重链即表示在这条链上的节点编号是连续的。即top[x]到x的路径的点编号是连续的。(特殊的,1个点也算一条重链)

    虽然量比较多,我也每次看到这里就不想学,但不用着急,等介绍了如何求后再去理解就不难了。

    如何预处理

    第一个dfs,求出depth,fa,sum,heavy_son

    这应该是老套路了,简单求解。

    void dfs1(int x,int father)
    {
    	int maxson=0,SON=0;
    	depth[x]=depth[father]+1;fa[x]=father;sum[x]=1;
    	for(int k=lnk[x];k;k=las[k])
    	if(nex[k]!=father)
    	{
    		dfs1(nex[k],x);
    		sum[x]+=sum[nex[k]];
    		if(sum[nex[k]]>maxson)maxson=sum[nex[k]],SON=nex[k];
    	}
    	heavy_son[x]=SON;
    }
    

    第二个dfs,求出id,top

    id数组按照枚举点的顺序就行了

    关于求top,如果当前访问的是x的重儿子,top[x的重儿子]就和top[x]是一样的。(因为按照先重儿子的顺序top[x]到x的重儿子的编号是连续的,如果不是重儿子,那么top[x的重儿子]就是x的重儿子。(新的一段连续编号)

    void dfs2(int x,int TOP)
    {
    	id[x]=++cnt;newt[cnt]=t[x];top[x]=TOP;
    	if(heavy_son[x])dfs2(heavy_son[x],TOP);
    	for(int k=lnk[x];k;k=las[k])
    	if(nex[k]!=fa[x]&&nex[k]!=heavy_son[x])dfs2(nex[k],nex[k]);
    }
    
  • 相关阅读:
    spingboot集成jpa(二)
    datanode与namenode的通信
    Yarn NodeManager restart
    hadoop上线和下线节点
    Spark读取文件
    eclipse安装中文补丁包
    eclipse中maven打包
    (转) eclipse安装lombok
    Windows 访问 Oracle
    wCF 问题收集页
  • 原文地址:https://www.cnblogs.com/DavidJing/p/10426543.html
Copyright © 2011-2022 走看看