luogu 3398 仓鼠找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”。

输入输出样例
**输入样例#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\le200,q\le200$

40%的数据 \(n\le2000,q\le2000\)

70%的数据 \(n\le50000,q\le50000\)

100%的数据 \(n\le100000,q\le100000\)

solution

这道题用裸的树剖求\(LCA\)就可以做出来。
但是我们要判断如何在两天路径上找相同的点。
经过多次画图发现,一条路径上的\(LCA\)一定会出现在另一条路径上。
所以我们就可以求\(LCA\)
那么我们需要判断哪两个条件呢?
设当前点\(x\),判断在\(a\)\(b\)这条路径上

1. deep[LCA(a,b)]>deep[LCA(c,d)]
2. LCA(LCA(a,b),c)==LCA(a,b)||LCA(LCA(a,b),d)==LCA(a,b)

这两个条件的意思是
如果\(LCA1\)\(LCA2\)要深,并且LCA2两个点中其中一个经过LCA1,那么就在一条路径上

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 200000;
int n,q;
struct edge {
	int next,to;
} e[N];
int head[N],tot,deep[N],fa[N],size[N],top[N],son[N],id[N],cnt,ind[N],root;
void add(int x,int y) {
	e[++tot].next=head[x];
	head[x]=tot;
	e[tot].to=y;
}
void dfs1(int x,int f) {
	fa[x]=f;
	size[x]=1;
	for(int i=head[x]; i; i=e[i].next) {
		int v=e[i].to;
		if(v!=f && !deep[v]) {
			deep[v]=deep[x]+1;
			dfs1(v,x);
			size[x]=size[v]+size[x];
			if(size[v]>size[son[x]]) son[x]=v;
		}
	}
}
void dfs2(int x,int topf) {
	id[x]=++cnt;
	top[x]=topf;
	if(!son[x]) return;
	dfs2(son[x],topf);
	for(int i=head[x]; i; i=e[i].next) {
		int v=e[i].to;
		if(v!=fa[x] && !id[v])
			dfs2(v,v);
	}
}
int LCA(int x,int y) {
	while(top[x]!=top[y]) {
		if(deep[top[x]]<deep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return deep[x]<=deep[y]? x:y;
}/*
bool judge(int lca,int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        x=fa[top[x]];
        if(x==lca)return true;
    }
    return false;
}*/
int main() {
	cin >> n >> q;
	for(int i=1; i<=n-1; i++) {
		int a,b;
		cin >> a >> b;
		add(a,b);
		add(b,a);
	}
	root=1;
	deep[1]=1;
	dfs1(1,1);
	dfs2(1,1);
	while(q--) {
		int a,b,c,d;
		cin >> a >> b >> c >> d;
		int S=LCA(a,b);
		int T=LCA(c,d);
		if(deep[S]<deep[T]){
			swap(a,c);
			swap(b,d);
			swap(S,T);
		}
		if(LCA(S,c)==S||LCA(S,d)==S)puts("Y");
		else puts("N");
	}
}
posted @ 2018-08-17 20:28  _Lancy  阅读(173)  评论(0编辑  收藏  举报