前言
先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构来维护每一条链,许多比赛都会用到这个方法。
相关概念
重结点:子树结点数目最多的结点; 
 轻节点:父亲节点中除了重结点以外的结点; 
 重边:父亲结点和重结点连成的边; 
 轻边:父亲节点和轻节点连成的边; 
 重链:由多条重边连接而成的路径; 
 轻链:由多条轻边连接而成的路径;
相关数组定义
s[x] 保存以x为根的子树节点个数 
 top[x] 保存当前节点所在链的顶端节点 
 son[x] 保存重儿子 
 dep[x] 保存结点x的深度值 
 fa[x] 保存结点x的父亲节点 
 id[x] 保存树中每个节点剖分以后的新编号(DFS的执行顺序) 
 rank[x] 保存当前节点在树中的位置
相关性质
1、ž轻边(U,V),size(V)<=size(U)/2。 
 2、ž从根到某一点的路径上,不超过O(logN)条轻边,不超过O(logN)条重路径。 
 因为性质2,树链剖分就有了一个很不错的时间复杂度。
具体实现
1、第一遍dfs求出所以节点的s,son,dep,fa。
void dfs(int x)
{
    int t=0;si[x]=1;
    for(int i=lst[x];i;i=nxt[i])
        if(to[i]!=fa[x])
        {
            dep[to[i]]=dep[x]+1;
            fa[to[i]]=x;
            dfs(to[i]);
            si[x]+=si[to[i]];
            if(si[to[i]]>t)t=si[to[i]],son[x]=to[i];
        }
}
2、第二遍dfs, 
 按照重儿子优先的顺序,跟所以点重新编号,并求出每个点所在重链的链顶。
void dfs_(int x,int t)
{
    id[x]=++now;
    rank[now]=x;
    top[x]=t;
    if(son[x])dfs_(son[x],t);
    for(int i=lst[x];i;i=nxt[i])
        if(to[i]!=fa[x] && to[i]!=son[x])
            dfs_(to[i],to[i]);
}两遍dfs之后,树链剖分就可了,剩下就是用数据结构去维护了。 
 在重新的编号中,重链是连续的一段。 
 查询两个点之间的信息时,先查找lca。 
 具体做法: 
 判断两个点是否在同一条重链上,如果是,lca就是在这条重链上了。 
 如果不是,选择深度(链顶)较大的重链向上跳一条重链(类似求lca)。 
 不断重复上面的操作,直到找到lca为止。
每向上跳一次,都记录下需要查询的信息。 
 因为从根到某一点的路径上,不超过O(logN)条轻边,不超过O(logN)条重路径,那么查询的复杂度就是
  
   O(logn∗数据结构复杂度)
  
 
                   
                   
                   
                   
                             
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   1265
					1265
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            