Link
题目
思路
树形结构求两点间的最短路可用LCA,然后我们可以发现,两条路如果相交的话其中一条路的两点的LCA必定是在另一条路上的。
Code
#include<cstdio>
#include<algorithm>
using namespace std;
int n,q,t;
int l[500001],jump[500001],Deep[500001],father[500001][101];
struct asdf{
int to,next;
} A[1000001];
void read(){ //读入
int x,y;
scanf("%d%d", &n, &q);
for(int i = 1; i < n; ++i){
scanf("%d%d", &x, &y);
A[++t] = (asdf){y,l[x]}; l[x] = t; //邻接表存储
A[++t] = (asdf){x,l[y]}; l[y] = t;
}
int k = 1;
jump[1] = 1; //预处理jump。jump[i]为在深度为i的时候可以跳2^(i-1)的步数
for(int i = 2; i <= n; ++i){
jump[i] = jump[i-1];
if(i / k == 2){
k*=2;
++jump[i];
}
}
}
void dfs(int now,int fu){ //当前点和父亲//dfs求某节点跳2^k步是哪个节点
father[now][0] = fu; //跳2^0步
Deep[now] = Deep[fu] + 1; //深度统计
for(int i = 1; i <= jump[Deep[now]]; ++i)
father[now][i] = father[father[now][i-1]][i-1];
//从当前点跳2^i步=跳了2^(i-1)步的点后再跳2^(i-1)步
for(int i = l[now]; i; i = A[i].next)
if(Deep[A[i].to] == 0) dfs(A[i].to,now);
}
int lca(int x,int y){
if(Deep[x]>Deep[y]){ //让y的深度大于x的深度
int l = x;
x = y;
y = l;
}
while(Deep[x] != Deep[y]) y = father[y][jump[Deep[y] - Deep[x]] - 1];
//让x和y跳到同一高度 //y跳的时候就有倍增跳跃
if(x == y) return x;
for(int i = jump[Deep[x]]-1; i>=0; --i) //跳跃
if(father[x][i] != father[y][i]){ //如果父亲不一样就跳过去
//如果父亲一样可能会跳过头 //所以我们的目标是最近公共祖先的子节点
x = father[x][i];
y = father[y][i];
}
return father[x][0]; //返回
}
int vis(int xx,int yy){
int lll = lca(xx,yy);
return Deep[xx]-Deep[lll] + Deep[yy]-Deep[lll];
}
int main(){
read();
dfs(1,0); //先dfs
for(int i = 1; i <= q; ++i){
int a,b,c,d,xx,yy;
scanf("%d%d%d%d",&a,&b,&c,&d);
xx = lca(a,b); yy = lca(c,d);
if(vis(a, yy)+vis(b, yy)==vis(a, b) || vis(c, xx)+vis(d, xx)==vis(c, d)) printf("Y\n"); //判断一下是否相交。
else printf("N\n");
}
}