• 树的直径


    传送门啦

    思路:

    dfs做法:

    详细地说,这个做法包含两步:
    1.从任意节点出发,通过 $ DFS $ 对树进行一次遍历,求出与出发点距离最远的节点记为 $ p $
    2.从节点 $ p $ 出发,通过 $ DFS $再进行一次遍历,求出与 $ p $ 距离最远的节点,记为 $ q $ 。
    从 $ p $ 到 $ q $ 的路径就是树的一条直径。因为 $ p $ 一定是直径的一端,否则总能找到一条更长的链,与直径的定义矛盾。 $ p $ 为直径的一端,那么自然的,与 $ p $ 最远的 $ q $ 就是直径的另一端。
    在第2步的遍历中,可以记录下来每个点第一次被访问的前驱节点。最后从 $ q $ 递归到 $ p $ ,即可得到直径的具体方案
    (代码中是从一号点出发找到 $ pos $ ,再从 $ pos $ 访问到1)

    #include <iostream> 
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define re register
    using namespace std ;
    const int maxn = 5 * 1e5 + 4 ;
    
    inline int read () {
    	int f = 1 , x = 0 ;
    	char ch = getchar () ;
    	while (ch > '9' || ch < '0') {if(ch == '-') f = -1 ; ch = getchar () ;}
    	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0' ; ch = getchar () ;}
    	return x * f ;
    }
    
    int n , q , u , v , a , b , c , d ;
    int head[maxn] , tot ;
    
    struct Edge {
    	int from , to , next ;
    }edge[maxn << 1] ;
    
    inline void add (int u , int v) {
    	edge[++tot].from = u ;
    	edge[tot].to = v ;
    	edge[tot].next = head[u] ;
    	head[u] = tot ;
    }
    
    int dep[maxn] , f[maxn][21] ;
    
    inline void dfs (int x , int fa) {
    	dep[x] = dep[fa] + 1 ;
    	f[x][0] = fa ;
    	for(re int i = 1 ; (1 << i) <= dep[x] ; ++ i) {
    		f[x][i] = f[f[x][i - 1]][i - 1] ;
    	}
    	for(re int i = head[x] ; i ; i = edge[i].next) {
    		int v = edge[i].to ;
    		if(v != fa) dfs(v , x) ;
    	}
    }
    
    inline int lca (int a , int b) {
    	if(dep[a] < dep[b])  swap(a , b) ;
    	for(re int i = 18 ; i >= 0 ; -- i) {
    		if((1 << i) <= (dep[a] - dep[b])) {
    			a = f[a][i] ;
    		}
    	}
    	if(a == b)  return a ;
    	for(re int i = 18 ; i >= 0 ; -- i) {
    		if((1 << i) <= dep[a] && f[a][i] != f[b][i]) {
    			a = f[a][i] ;
    			b = f[b][i] ;
    		}
    	}
    	return f[a][0] ; 
    }
    
    int main () {
    	n = read () ; q = read () ;
    	for(re int i = 1 ; i <= n - 1 ; ++ i) {
    		u = read () ; v = read () ;
    		add(u , v) ;
    		add(v , u) ;
    	}
    	dfs(1 , 1) ; 
    	for(re int i = 1 ; i <= q ; ++ i) {
    		a = read () ; b = read () ; c = read () ; d = read () ;
    		int fm1 = max(dep[lca(a , b)] , dep[lca(c , d)]) ;
    		int fm2 = max(max(dep[lca(a , c)] , dep[lca(a , d)]) , max(dep[lca(b , c)] , dep[lca(b , d)])) ;
            if(fm2 >= fm1)
    			printf("Y
    ");
            else
        		printf("N
    ");
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    php留言
    linux系统的初化始配置
    Alertmanager 配置解析
    Prometheus 配置解析
    Prometheus Consul 自动发现
    测试find 命令删除文件速度
    win10 安装wsl2 centos
    kubernetes api 的两种身份认证 以及kubectl生成kubeconfig
    Elasticsearch集群平滑下线data节点
    Fiddler Everywhere 安卓手机抓包配置
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/10440469.html
Copyright © 2020-2023  润新知