• 【树剖求LCA】树剖知识点


    不太优美但是有注释的版本:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    struct edge{
        int to,ne;
    }e[1000005];
    int n,m,s,ecnt,head[500005],dep[500005],siz[500005],son[500005],top[500005],f[500005];
    void add(int x,int y)    //加边
    {
        e[++ecnt].to=y;
        e[ecnt].ne=head[x];
        head[x]=ecnt;
    }
    void dfs1(int x)                             //构造树
    {
        siz[x]=1;                                //假设当前节点仅有一个儿子
        dep[x]=dep[f[x]]+1;                      //当前节点深度=父亲节点深度+1
        for(int i=head[x];i;i=e[i].ne)          //遍历所有的子节点
        {
            int dd=e[i].to;
            if(dd==f[x])continue;               //如果是父节点,则略过
            f[dd]=x;                             //那么确定x是当前节点的父亲
            dfs1(dd);                            //向下遍历
            siz[x]+=siz[dd];                     //遍历完子树之后,加上子树的大小
            if(!son[x]||siz[son[x]]<siz[dd])    //如果x节点重儿子未确定或者重儿子的子树比当前遍历节点的子树小
                son[x]=dd;                       //更新重儿子
        }
    }
    
    void dfs2(int x,int tv)                     //求重链
    {
        top[x]=tv;                               //设置x所在重链顶为tv
        if(son[x])dfs2(son[x],tv);              //如果x有重儿子,那么随着这条重链走
        for(int i=head[x];i;i=e[i].ne)            
        {
            int dd=e[i].to; 
            if(dd==f[x]||dd==son[x])continue;  //如果走到父亲或者走到重儿子(已经走过重儿子,避免重复),那么跳过
            dfs2(dd,dd);                        //开启一条新链,链顶是其本身
        }
    }
    int lca(int x,int y)
    {
    	while(top[x]!=top[y])                              //如果二者不在同一条重链上
        { 
    		if(dep[top[x]] >= dep[top[y]]) x=f[top[x]];   //选择所在重链的顶的深度较大的点向上跳,目的是防止跳过LCA
    		else y=f[top[y]];
    	}
    	return dep[x] < dep[y] ?x :y;                     //当二者在同一条重链上的时候,选择深度较浅的点即为lca
    	
    	
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&s);
        for(int i=1;i<n;++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs1(s);
        dfs2(s,s);
        for(int i=1;i<=m;++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
    }
    

      

    比较优美但是没注释的版本:

    #include<iostream>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const ll INF=99999999;
    const int N = 500010;
    
    int n,m,s;
    
    struct edge{
    	int to,ne;
    	
    }e[N*2];
    
    int top[N],siz[N],son[N],fa[N],dep[N];
    int head[N],ecnt = 1;
    
    void add(int x,int y)
    {
    	e[ecnt].to = y;
    	e[ecnt].ne = head[x];
    	
    	head[x] = ecnt++;
    }
    
    void dfs1(int x)
    {
    	siz[x] = 1;
    	dep[x] = dep[fa[x]] + 1;
    	
    	for(int i = head[x];i;i = e[i].ne){
    		int t = e[i].to;
    		if(t == fa[x]) continue;
    		fa[t] = x;
    		
    		dfs1(t);
    		siz[x] += siz[t];
    		if(!son[x]||siz[son[x]] < siz[t])
    			son[x] = t;
    	}
    }
    
    void dfs2(int x,int tp)
    {
    	top[x] = tp;
    	
    	if(son[x])
    		dfs2(son[x],tp);
    		
    	for(int i = head[x];i;i = e[i].ne){
    		int t = e[i].to;
    		if(t == son[x]||t == fa[x]) continue;
    		
    		dfs2(t,t);
    	}	
    
    }
    
    int lca(int x,int y)
    {
    	while(top[x] != top[y]){
    		if(dep[top[x]] >= dep[top[y]]) x = fa[top[x]];
    		else y = fa[top[y]];
    	}
    	return dep[x] < dep[y] ?x :y;
    }
    int main()
    {
    	
    	scanf("%d%d%d",&n,&m,&s);
    	for(int i = 1;i < n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		
    		add(x,y);
    		add(y,x);
    	}
    	dfs1(s);
    	dfs2(s,s);
    	
    	for(int i = 1;i <= m;i++){
    		int a,b;
    		scanf("%d%d",&a,&b);
    		
    		printf("%d
    ",lca(a,b));
    	}
    	return 0;
    }
    

    树剖理解容易,需要注意的是题目如果给的是双向边,e数组需要开两倍于边数

      

  • 相关阅读:
    移动端
    vue2.0实战记录
    vue学习记录
    JS中数字计算精度
    10亿个字符串的排序问题
    <nginx.conf> nginx用户权限
    详解jquery插件中;(function ( $, window, document, undefined )的作用
    nginx服务器安装及配置文件详解
    移动端HTML5<video>视频播放优化实践
    打造自己的html5视频播放器
  • 原文地址:https://www.cnblogs.com/dudujerry/p/10192526.html
Copyright © 2020-2023  润新知