LCA判公共点 仓鼠找sugar(洛谷 P3398)

仓鼠找sugar

题目描述

小仓鼠的和他的基(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”。


这道题最重要的推论就是:当两个点 a,b 的lca在另外两个点 c,d 的连线上时,a,b线段 和 c,d线段 相交;

知道这个还要知道一个:怎么判断一个点是否在由两个点相连的线段上?这跟判断一个点是否在 i到j 的最短路上是一样的;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=200100;
const int M=1000100;
const LL mod=100000000;
int n,q,head[N],cnt,lg[N],dep[N],fa[N][40],in[N];
struct Node{
	int to,nex;
}edge[M];
void add(int p,int q){
	edge[cnt].to=q;
	edge[cnt].nex=head[p];
	head[p]=cnt++;
}
void dfs(int sn,int ft){
	dep[sn]=dep[ft]+1,fa[sn][0]=ft;
	for(int i=1;i<=lg[dep[sn]];i++) fa[sn][i]=fa[fa[sn][i-1]][i-1];
	for(int i=head[sn];~i;i=edge[i].nex){
		if(edge[i].to!=ft) dfs(edge[i].to,sn);
	}
}
int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y]) x=fa[x][lg[dep[x]-dep[y]]-1];
	if(x==y) return x;
	for(int k=lg[dep[x]]-1;k>=0;k--){
		if(fa[x][k]!=fa[y][k]){
			x=fa[x][k],y=fa[y][k];
		}
	}
	return fa[x][0];
}
int main(){
    memset(head,-1,sizeof(head));
    cin>>n>>q;
	for(int i=1;i<n;i++){
		int p,q;
		scanf("%d%d",&p,&q);
		in[q]++;
		add(p,q),add(q,p);
	} 
	for(int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);//预处理(log_2(i))+1的值 
	int st=1;
	for(int i=1;i<=n;i++) if(in[q]==0) st=i;
	dfs(st,0);
	while(q--){
		int a,b,c,d;
		scanf("%d%d%d%d",&a,&b,&c,&d);
		int e=lca(a,b);
		int cd=dep[c]+dep[d]-2*dep[lca(c,d)];
		int ce=dep[c]+dep[e]-2*dep[lca(c,e)];
		int ed=dep[e]+dep[d]-2*dep[lca(e,d)];
		if(ce+ed==cd) cout<<"Y"<<endl;
		else{
			int e=lca(c,d);
			int ab=dep[a]+dep[b]-2*dep[lca(a,b)];
			int ae=dep[a]+dep[e]-2*dep[lca(a,e)];
			int eb=dep[e]+dep[b]-2*dep[lca(e,b)];
			if(ae+eb==ab) cout<<"Y"<<endl;
			else cout<<"N"<<endl;
		}
	}
    return 0;
}
发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/104973988