洛谷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\n");
        else
            printf("N\n");
    }
    return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/Stephen-F/p/10439448.html