1. 程式人生 > >[Luogu 3398] 倉鼠找sugar

[Luogu 3398] 倉鼠找sugar

[Luogu 3398] 倉鼠找sugar

<題目連結>


又是 LCA…

前兩天死活寫不過的一個題今天終於順手切了。

思路嘛參考了一樓題解。

就是說,對於 a, b, c, d 四個點,

x = LCA(a, b), y = LCA(c, d),

兩條路徑有交叉,當且僅當 c, d 至少一個在 x 的子樹下,且 a, b 至少一個在 y 的子樹下。

由於我是 HLD 求的 LCA,第一遍 DFS 時順手把子樹大小求了,後邊判斷在不在一棵子屬下的時候就可以很方便了。

就這樣。

#include <algorithm>
#include <cstdio>

const int MAXN = 100010; 

int n, q; 

struct Graph
{
    struct Edge
    {
        int to; 
        Edge *next; 
        Edge(int to, Edge* next): to(to), next(next) {}
        ~Edge(void)
        {
            if(next != NULL)
                delete next; 
        }
    }*head[MAXN]; 
    Graph(int n)
    {
        std :: fill(head + 1, head + n + 1, (Edge*)NULL); 
    }
    ~Graph(void)
    {
        for(int i = 1; i <= n; ++i)
            delete head[i]; 
    }
    void AddEdges(int u, int v)
    {
        head[u] = new Edge(v, head[u]); 
        head[v] = new Edge(u, head[v]); 
    }
}*G; 

namespace HLD
{
    int num; 
    struct Node
    {
        int depth, father, son, top, size, DFN; 
    }s[MAXN]; 
    void DFS1(int u, int k)
    {
        s[u].depth = k; 
        s[u].size = 1; 
        int v; 
        for(Graph :: Edge *i = G -> head[u]; i != NULL; i = i -> next)
            if(!s[v = i -> to].size)
            {
                DFS1(v, k + 1); 
                s[u].size += s[v].size; 
                s[v].father = u; 
                if(s[v].size > s[s[u].son].size)
                    s[u].son = v; 
            }
    }
    void DFS2(int u, int top)
    {
        s[u].top = top; 
        s[u].DFN = ++num; 
        if(s[u].son)
            DFS2(s[u].son, top); 
        int v; 
        for(Graph :: Edge *i = G -> head[u]; i != NULL; i = i -> next)
            if(!s[v = i -> to].DFN)
                DFS2(v, v); 
    }
    void Init(void)
    {
        DFS1(1, 1); 
        DFS2(1, 1); 
    }
    int LCA(int x, int y)
    {
        int a, b; 
        while((a = s[x].top) ^ (b = s[y].top))
            if(s[a].depth > s[b].depth)
                x = s[a].father; 
            else
                y = s[b].father; 
        return s[x].depth < s[y].depth ? x : y; 
    }
    bool Range(int x, int y)
    {
        return s[x].DFN <= s[y].DFN && s[y].DFN < s[x].DFN + s[x].size; 
    }
    bool Query(int a, int b, int c, int d)
    {
        int x = LCA(a, b), y = LCA(c, d); 
        return (Range(x, c) || Range(x, d)) && (Range(y, a) || Range(y, b)); 
    }
}

int main(void)
{
    scanf("%d %d", &n, &q); 
    G = new Graph(n); 
    for(int i = 1, u, v; i < n; ++i)
    {
        scanf("%d %d", &u, &v); 
        G -> AddEdges(u, v); 
    }
    HLD :: Init(); 
    for(int i = 1, a, b, c, d; i <= q; ++i)
    {
        scanf("%d %d %d %d", &a, &b, &c, &d); 
        puts(HLD :: Query(a, b, c, d) ? "Y" : "N"); 
    }
    return 0; 
}

謝謝閱讀。