【洛谷 3398】 仓鼠找sugar

67 篇文章 0 订阅
8 篇文章 0 订阅

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

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


输入格式

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

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

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

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


输入输出样例
输入
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

输出
Y
N
Y
Y
Y


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

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

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

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

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


解题思路
题意:现有 A , B , C , D A,B,C,D A,B,C,D四点,判断 A A A B B B的最短路和 C C C D D D的最短路有无交汇

以下为结论:
先套两遍 l c a lca lca,把 A A A B B B的, C C C D D D的最近公共祖先求出来,然后求出 A A A D D D B B B C C C l c a lca lca深度最大的,把得到的深度与 A A A B , C B,C BC D D D l c a lca lca深度作比较。如果都大于等于 A A A B B B C C C D D D l c a lca lca深度,则输出 “ Y ” “Y” Y,否则输出 “ N ” “N” N

推导:
在这里插入图片描述
从上图可以很容易得出:

  • A → B A→B AB l c a lca lca是2,深度为2
    C → D C→D CD l c a lca lca是1,深度为1
    A → D A→D AD l c a lca lca是1,深度为1
    B → C B→C BC l c a lca lca是2,深度为2

m a x max max后比较,都是大于等于,输出Y。。。
多推几组数据,就能理解啦↖( ^ ω ^ )↗


代码

#include<bits/stdc++.h>
using namespace std;
int n,q,u,v,k,l,r,ll,rr,a1,a2,a3,a4,dep[100010],f[100010][22],head[100010],lg[100010];
struct c{
	int x,next;
}a[200010];
void add(int x,int y){
	a[++k].x=y;
	a[k].next=head[x];
	head[x]=k;
}
void dfs(int x,int fa){
	f[x][0]=fa,dep[x]=dep[fa]+1;
	for(int i=1;i<=lg[dep[x]];i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=head[x];i;i=a[i].next){
		int t=a[i].x;
		if(t!=fa)
			dfs(t,x);
	}
}
int LCA(int x,int y){
	if(dep[x]>dep[y])
		swap(x,y);
	while(dep[y]>dep[x])
		y=f[y][lg[dep[y]-dep[x]]-1];
	if(x==y)
		return x;
	for(int i=lg[dep[x]]-1;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{	
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=n;i++)
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	dfs(1,0);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d%d%d",&l,&r,&ll,&rr);
		a1=dep[LCA(l,r)];
		a2=dep[LCA(ll,rr)];
		a3=dep[LCA(l,rr)];
		a4=dep[LCA(ll,r)];
		a4=max(a4,a3);
		if(a4>=a1&&a4>=a2)
			printf("Y\n");
		else printf("N\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值