• 洛谷P3398 仓鼠找suger


    传送门啦

    思路:

    那么从 $ A $ 到 $ B $ 可以分解成 先从 $ A $ 到 $ X $ 再从 $ X $ 到 $ B $ 。。。 另一个同理

    假设能相遇 那么
    要么在 $ A $ 到 $ X $ 的过程 $ A,B $ 相遇 要么在 $ X $ 到 $ B $ 的过程 $ A,B $ 相遇
    对于在 $ A $ 到 $ X $ 的过程相遇的情况 又可以分解为:
    情况1:
    在 $ A $ 到 $ X $ 的过程和 $ C $ 到 $ Y $ 的过程 中 $ A,B $ 相遇
    情况2:
    在 $ A $ 到 $ X $ 的过程和 $ Y $ 到 $ D $ 的过程 中 $ A,B $ 相遇

    呃呃呃。。。

    相遇的情况 :
    $ a->X , c->Y $ 相遇(可以认为 松鼠和他基友都在网上冲)
    $ a->X,Y->d $ 相遇(一个往上冲,一个在往下冲)
    $ X->b,c->Y $ 相遇(一个往下冲 一个往上冲)
    $ X->b,Y->d $ 相遇(都往下冲)
    根据树中的每一个节点的父亲都是唯一的, $ lca $ 可以认为是他们最短路径上深度最浅的那个点, $ a,b,c,d $ 到他们 $ lca $ 的路径是唯一的。

    而上述的 $ 4 $ 个 $ lca $ 中深度最大的那一个 我们姑且记为 $ S $ ,那么 $ S $ 一定是 $ a,b $ 中的一个和 $ c,d $ 的一个的 $ lca $ (我们假设是 $ lca(a,d) $ )

    那么如果 $ S $ 的深度大于 $ x,y $ 中较大的的那一个,说明 $ a $ 在和 $ d $ 在往上冲的过程中一定要经过他们的 $ lca $ ,也就是 $ S $ ,再经过 $ x $ 或者是 $ y $ 。因为 $ a $ 和 $ d $ 是 $ a,b $ 中的一个和 $ c,d $ 中的一个,他们还要冲向 $ X $ 或者是 $ Y $ 。这种情况必然相遇;

    在 $ X 、Y $ 中取一个最大,再在 $ lca(a,c).lca(a,d),lca(b,c),lca(b,d) $ 这四个当中取一个最大,如果后者的深度大于等于前者,那么可以相遇,否则不能;

    #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 ;
    }
    
  • 相关阅读:
    Filter and Listener
    Cookie Session
    怎样快速将一台电脑虚拟机导入另外一台电脑
    网页下载文件服务端代码
    图片验证码生成代码
    Request实战
    Response
    设置页眉页脚的距离
    页眉页脚的设置
    节的设置
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/10439448.html
Copyright © 2020-2023  润新知