LCA 仓鼠找sugar

题意:一棵树, Aab A 要 从 a 号 节 点 走 到 b 号节点, Bxy B 要 从 x 号 节 点 走 到 y 号节点。每次给出一组 (a,b)(x,y) ( a , b ) 和 ( x , y ) 。问这两条路径是否有重合部分(包括一个点)。

             这个问题需要进行分类讨论。首先,如果 lca(a,b) l c a ( a , b ) 的深度大于 xy x 和 y 的深度,或者 lca(x,y) l c a ( x , y ) 的深度大于 ab a 和 b 的深度,显然都是不行的。
             对于两条路径有重合的情况,一定是两个点的 lca l c a 在另外两个点的路径上。如果两条路径有重合部分,就应该是以下的这种情况:这里 p=lca(a,b)q=lca(x,y) p = l c a ( a , b ) , q = l c a ( x , y )

dep[p]>=dep[q]
lca(x,p)=p||lca(y,p)=p;

dep[p]<dep[q]
lca(a,q)=q||lca(b,q)=q

             其余的不满足以上两种情况的均为无重合部分。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
struct node
{
    int next,to;
}e[1001000];
int n,q,num,head[1001000];
int dep[1001000],f[500500][25];
void add(int from,int to)
{
    e[++num].next=head[from];
    e[num].to=to;
    head[from]=num;
}
void dfs(int x,int fa)
{
    dep[x]=dep[fa]+1;
    f[x][0]=fa;
    for(int i=1;(1<<i)<=dep[x];++i)
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)
            continue;
        dfs(v,x);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])
        swap(x,y);
    for(int i=20;i>=0;--i)
        if(dep[x]-dep[y]>=(1<<i))
            x=f[x][i];
    if(x==y)
        return x;
    for(int i=20;i>=0;--i)
    {
        if(dep[x]>=(1<<i)&&f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }   
    }
    return f[x][0];
}
int main()
{
    cin>>n>>q;
    for(int i=1;i<=n-1;++i)
    {
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=q;++i)
    {
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        int p=lca(a,b);
        int q=lca(c,d);
        if(dep[p]>dep[c]&&dep[p]>dep[d])
        {
            printf("N\n");
            continue;
        }
        if(dep[q]>dep[a]&&dep[q]>dep[b])
        {
            printf("N\n");
            continue;
        }
        if(dep[p]>=dep[q])
        {
            if(lca(p,c)==p||lca(p,d)==p)
            {
                printf("Y\n");
                continue;               
            }
        }
        if(dep[p]<dep[q])
        {
            if(lca(q,a)==q||lca(q,b)==q)
            {
                printf("Y\n");
                continue;               
            }
        }
        printf("N\n");
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值