题解 P3398 【仓鼠找sugar】
其实,多画几个图模拟一下,可以发现如下一个神奇的规律:
如果两条路径相交,那么一定有一条路径的LCA在另一条路径上
而判断一个节点x,是否在路径s-t上需要满足如下几个条件
- deep[x]>=deep[LCA(s,t)]
- LCA(s,x)=x或LCA(t,x)=x;
所以分两种情况讨论一下即可
时间复杂度O(n log n)
下面是树剖LCA的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define MAXN 100000+15
using namespace std;
vector<int>vec[MAXN];
int n,q,v,u,a,b,c,d;
int deep[MAXN],dad[MAXN],size[MAXN],top[MAXN];
int dfs(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;
dfs(vec[x][i]);
size[x]+=size[vec[x][i]];
}
}
int dfs1(int x){
int t=0;
if(!top[x]) top[x]=x;
for(int i=0;i<vec[x].size();i++)
if(dad[x]!=vec[x][i]&&size[vec[x][i]]>size[t])
t=vec[x][i];
if(t){
top[t]=top[x];
dfs1(t);
}
for(int i=0;i<vec[x].size();i++)
if(dad[x]!=vec[x][i]&&vec[x][i]!=t)
dfs1(vec[x][i]);
}
int LCA(int x,int y){
for(;top[x]!=top[y];){
if(deep[top[x]]<deep[top[y]])
swap(x,y);
x=dad[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
return x;
}
int main(){
cin>>n>>q;
for(int i=1;i<n;i++){
cin>>u>>v;
vec[u].push_back(v);
vec[v].push_back(u);
}
dfs(1);
dfs1(1);
for(int i=1;i<=q;i++){
cin>>a>>b>>c>>d;
int S=LCA(a,b);
int T=LCA(c,d);
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;
}
}