首页 > 代码库 > luogu P3398 仓鼠找sugar x

luogu P3398 仓鼠找sugar x

 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 52 54 21 31 45 1 5 12 2 1 44 1 3 43 1 1 53 5 1 4
输出样例#1:
YNYYY

说明

本题时限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;}

 

luogu P3398 仓鼠找sugar x