iai 路径求交 题解

例题:路径求交

给定一棵树,问两条路径 a , b a,b a,b c , d c,d c,d是否有交点

iai 路径求交 题解_第1张图片

由于一段路径 u → v u\to v uv 等价于 u → l c a ( u , v ) u\to lca(u,v) ulca(u,v) l c a ( u , v ) → v lca(u,v) \to v lca(u,v)v

那么如图,如果 a → b a \to b ab c → d c \to d cd 有交点,那么 l c a ( c , d ) lca(c,d) lca(c,d) (深度较深的 l c a lca lca) 一定和 a → b a\to b ab 的两条等价路线其一有交点,由于 l c a ( c , d ) lca(c,d) lca(c,d) l c a ( a , b ) lca(a,b) lca(a,b) 深,因此一定是 a a a b b b 的直系祖先

#include
using namespace std;
const int MAXN=1e5+5;
int n,q,f[MAXN][20],dep[MAXN],lg[MAXN];
vector <int> G[MAXN];
int dfs(int u,int fa)
{
	f[u][0]=fa; dep[u]=dep[fa]+1;
	for(int i=1;i<=lg[dep[u]];i++)
		f[u][i]=f[f[u][i-1]][i-1];
	for(auto v:G[u])
	{
		if(v==fa) continue;
		dfs(v,u);
	}
}
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y])
		x=f[x][lg[dep[x]-dep[y]]];
	if(x==y) return x;
	for(int k=lg[dep[x]];k>=0;k--)
		if(f[x][k]!=f[y][k])
			x=f[x][k], y=f[y][k];
	return f[x][0];	
}
\
int main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++) lg[i]=log2(i);
	for(int i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,0);
	while(q--)
	{
		int a,b,x,y;
		cin>>a>>b>>x>>y;
		int lca1=lca(a,b), lca2=lca(x,y);
		//lca1 为较深的  lca2为较浅的
		if(dep[lca1]<dep[lca2]) swap(lca1,lca2), swap(a,x), swap(b,y);
		if(lca(lca1,x)==lca1 || lca(lca1,y)==lca1) puts("Y");
		else puts("N");
	
	}
	return 0;
}

你可能感兴趣的:(题解,图论,算法,深度优先)