【NOIP模擬賽】相交

在這裏插入圖片描述
題解:
因爲是樹所以路徑一定唯一,那麼我們先算出a,b的lca爲f1再算出c,d的lcaf2那麼不難發現是求是否有重合路徑,我們先把a到b的路徑拆成a到f1和b到f1兩條路徑,那麼就是求c到f2和前兩個是否有重合或者d到f2是否與前兩個有重合

#include<bits/stdc++.h>
using namespace std;
int head[100005];
int next[200005];
int ver[200005];
int d[100005];
int f[100005][25];
int tot=1,t;
int n,q;
int read(){
	int num=0;
	char ch=getchar();
	while(ch>'9'||ch<'0'){
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		num=(num<<1)+(num<<3)+ch-'0';
		ch=getchar();
	}
	return num;
}
void add(int x,int y){
	ver[++tot]=y;
	next[tot]=head[x];
	head[x]=tot;
}
void dfs(int x,int fa){
	d[x]=d[fa]+1;
	for(int j=1;j<=t;j++){
		f[x][j]=f[f[x][j-1]][j-1];
	}
	for(int i=head[x];i;i=next[i]){
		if(d[ver[i]]) continue;
		f[ver[i]][0]=x;
		dfs(ver[i],x);
	}
}
int lca(int x,int y){
	if(d[x]>d[y]) swap(x,y);
	for(int i=t;i>=0;i--){
		if(d[f[y][i]]>=d[x]) y=f[y][i];
	}
	if(x==y){
		return x;
	}
	for(int i=t;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int main(){
	n=read();
	t=log(n)/log(2)+1;
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	q=read();
	for(int i=1;i<=q;i++){
		int a=read(),b=read(),c=read(),d=read();
		int f1=lca(a,b),f2=lca(c,d);
		if(lca(a,c)==c && lca(c,f1)==f1 || lca(a,d)==d && lca(d,f1)==f1)
			printf("YES");
		else if(lca(b,c)==c && lca(c,f1)==f1 || lca(b,d)==d && lca(d,f1)==f1)
			printf("YES");
		else if(lca(b,f2)==f2 && lca(f1,f2)==f1 || lca(a,f2)==f2 && lca(f1,f2)==f1)
			printf("YES");
		else if(lca(c,f1)==f1 && lca(f1,f2)==f2 || lca(d,f1)==f1 && lca(f1,f2)==f2)
			printf("YES");
		else
			printf("NO");
		if(q)putchar('\n');
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章