luogu P3398 仓鼠找sugar

 P3398 仓鼠找sugar

    • 224通过
    • 860提交
  • 题目提供者 fjzzq2002
  • 标签 云端↑
  • 难度 提高+/省选-
  • 时空限制 1s / 128MB

题目描述

小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?

小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!

输入输出格式

输入格式:

第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。

接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。

接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。

输出格式:

对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。

输入输出样例

输入样例#1:
5 5
2 5
4 2
1 3
1 4
5 1 5 1
2 2 1 4
4 1 3 4
3 1 1 5
3 5 1 4
输出样例#1:
Y
N
Y
Y
Y

说明

本题时限1s,内存限制128M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。

20%的数据 n<=200,q<=200

40%的数据 n<=2000,q<=2000

70%的数据 n<=50000,q<=50000

100%的数据 n<=100000,q<=100000

思路:

  首先我们可以通过实践找到一个规律:

        若两条路径相交,那么一定有一条路径的lca在另一条路径上

  那么问题就简单多了,先敲一个求lca的板子,然后进行如下判断:

                - deep [ x ] >= deep [ lca ( s , t ) ]

                - lca ( s , x ) = x 或 lca ( t , x ) = x ; 

坑点:

  在进行判断是否有某一条路径的lca是否在另一条路径上的时候,记住要进行swap,比较deep比较靠下的那个lca才可以

上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;

const int N = 100100;
int n,q;
int deep[N],dad[N],size[N],top[N];
vector<int>vec[N];

inline int read()//优读 
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9')
    {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')
    {x=x*10+ch-'0';ch=getchar();}
    return x*f;  
}

void swap(int &a,int &b)
{//手写swap 
    int qwq=a;
    a=b;
    b=qwq;
}

void dfs1(int x)
{//寻找子节点个数以及深度,链头 
    size[x]=1;
    deep[x]=deep[dad[x]]+1;
    for(int i=0;i<vec[x].size();i++)
        if(dad[x]!=vec[x][i])
        {
            dad[vec[x][i]]=x;
            dfs1(vec[x][i]);
            size[x]+=size[vec[x][i]];
        }
}

void dfs2(int x)
{
    int tops=0;
    //如果该点没有链头,自己就是链头(蜜汁熟悉感2333) 
    if(!top[x])
        top[x]=x;
    //+3
    for(int i=0;i<vec[x].size();i++)
        //如果是当前点的子节点:
        //寻找子节点中子节点最多的节点 
        //(找重链)
        if(dad[x]!=vec[x][i] && size[vec[x][i]]>size[tops])
            tops=vec[x][i];
    if(tops)
    {
        top[tops]=top[x];
        dfs2(tops);
    }
    for(int i=0;i<vec[x].size();i++)
        //是子节点并且不在重链上 
        if(dad[x]!=vec[x][i] && vec[x][i]!=tops)
            dfs2(vec[x][i]);
}

inline int lca(int x,int y)
{
    while(top[x]!=top[y])//若不在一条链上 
    {
        if(deep[top[x]]<deep[top[y]])
        //将 x 的链头手动设置为比较靠下的那个点 
            swap(x,y);
        //从链头往上跳 
        x=dad[top[x]];
    }
    //lca一定是比较靠上的那个 
    if(deep[x]>deep[y])
        swap(x,y);
    return x;
}

int main()
{
    n=read(),q=read();
    for(int i=1,u,v;i<n;i++)
    {
        u=read(),v=read();
        vec[u].push_back(v),vec[v].push_back(u);
    }
    dfs1(1);
    dfs2(1);
    for(int i=1,a,b,c,d;i<=q;i++)
    {
        a=read(),b=read(),c=read(),d=read();
//      printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
        int S=lca(a,b),T=lca(c,d);
//      printf("%d %d LCA=\n%d %d LCA=\n",a,b,S,c,d,T);
        //寻找比较靠下的点 

        /* 
        错误×(大概是应该直接进行交换???) 
        if(deep[S]<deep[T])
            if(lca(T,a)==T || lca(T,b)==T)
            cout<<"Y"<<endl;
        else if(deep[S]>deep[T])
            if(lca(S,c)==S || lca(S,d)==S)
            cout<<"Y"<<endl;
        */

        if(deep[S]<deep[T])
        {
            swap(S,T);
            swap(a,c);
            swap(b,d);
        }
        //判断一下 
        if(lca(S,c)==S || lca(S,d)==S)
            cout<<"Y"<<endl;
        else
            cout<<"N"<<endl;
    }
    return 0;
}

 

posted @ 2017-07-17 17:20  夜雨声不烦  阅读(150)  评论(0编辑  收藏  举报