ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树链剖分 [模板]最近公共祖先LCA

2019-10-05 12:04:15  阅读:312  来源: 互联网

标签:10000010 sz ch 剖分 int 树链 LCA include 节点


 

本人水平有限,题解不到为处,请多多谅解

 

 本蒟蒻谢谢大家观看

 

题目:传送门

树链剖分:跑两遍dfs,第一遍找重边,第二遍找重链。

重儿子:父亲节点的所有儿子中子树结点数目最多(size最大)的结点;

轻儿子:父亲节点中除了重儿子以外的儿子;

重边:父亲结点和重儿子连成的边;

轻边:父亲节点和轻儿子连成的边;

重链:由多条重边连接而成的路径;

轻链:由多条轻边连接而成的路径

son[]表示重儿子,top[]表示重链所在的第一个节点,sz[]表示子节点数,fa[]表示父亲节点

图示:

 

 

 code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#pragma GCC optimize(3)

using namespace std;
int n,q,tot,s;
int head[1000010],nxt[10000010],ver[10000010],son[10000010],sz[10000010];
int top[10000010],dep[10000010],fa[10000010];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
inline void write(int x){
     char F[200];
     int tmp=x>0?x:-x ;
     if(x<0)putchar('-') ;
     int cnt=0 ;
        while(tmp>0)
        {
            F[cnt++]=tmp%10+'0';
            tmp/=10;
        }
        while(cnt>0)putchar(F[--cnt]) ;
}
void add(int x,int y){//字符链 
    ++tot;
    ver[tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void dfs1(int x){
    sz[x]=1;//自己算一个节点 
    son[x]=0;//自己的重儿子初始为0 
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y!=fa[x]){
            fa[y]=x;//上 : y 的父亲节点为 x 
            dep[y]=dep[x]+1;//中 : y的深度比x的深度多一 
            dfs1(y);//先遍历子树 
            sz[x]+=sz[y];//  下 :x的总结点数==字节点总数之和 
            if(sz[son[x]]<sz[y])
                son[x]=y; //不断更新重儿子 
        }
    } 
    return ;
}
void dfs2(int x,int tp){//tp为x这条链的初始节点 
    top[x]=tp;//x的初始节点为tp 
    if(son[x]!=0)//若有重儿子 
        dfs2(son[x],tp);//遍历重儿子
        //注意:此时重儿子的初始节点也为tp 
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y!=son[x]&&y!=fa[x])//如果y既不在重儿子中,也不可能为父亲节点 
            dfs2(y,y);//遍历y,因为son[x]已经遍历过了 
    }    
}
int query(int u,int v){//查找u,v的LCA 
    while(top[u]!=top[v]){//如果u,v不在一条链上 
        if(dep[top[u]]<dep[top[v]])//如果u的深度浅的话,要交换 
            swap(u,v); //因为有可能向上跳的过程越过了LCA,保证深度必须超过其LCA 
        u=fa[top[u]];//向上跳 
    }
    if(top[u]==top[v]){//如果在一条链上 
        if(dep[u]<dep[v])//输出深度浅的,因为深度越浅代表在上面,为u,v的LCA 
            return u;
        else
            return v;
    }
}
int main()
{
    n=read(),q=read(),s=read();
    for(int i=1;i<n;i++){
        int x,y;
        x=read(),y=read();
        add(x,y),add(y,x);
    }
    dfs1(s);//以s为根 
    dfs2(s,s);//以s为根,s为初始节点 
    for(int i=1;i<=q;i++){
        int a,b;
        a=read(),b=read();
        printf("%d\n",query(a,b));
    }
    return 0;
}

 树链剖分一定程度上类似于倍增,都是先确定大概范围,在具体寻找

标签:10000010,sz,ch,剖分,int,树链,LCA,include,节点
来源: https://www.cnblogs.com/nlyzl/p/11624304.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有