E. 1-Trees and Queries--------------------思維(LCA)

Gildong was hiking a mountain, walking by millions of trees. Inspired by them, he suddenly came up with an interesting idea for trees in data structures: What if we add another edge in a tree?

Then he found that such tree-like graphs are called 1-trees. Since Gildong was bored of solving too many tree problems, he wanted to see if similar techniques in trees can be used in 1-trees as well. Instead of solving it by himself, he’s going to test you by providing queries on 1-trees.

First, he’ll provide you a tree (not 1-tree) with n vertices, then he will ask you q queries. Each query contains 5 integers: x, y, a, b, and k. This means you’re asked to determine if there exists a path from vertex a to b that contains exactly k edges after adding a bidirectional edge between vertices x and y. A path can contain the same vertices and same edges multiple times. All queries are independent of each other; i.e. the added edge in a query is removed in the next query.

Input
The first line contains an integer n (3≤n≤105), the number of vertices of the tree.

Next n−1 lines contain two integers u and v (1≤u,v≤n, u≠v) each, which means there is an edge between vertex u and v. All edges are bidirectional and distinct.

Next line contains an integer q (1≤q≤105), the number of queries Gildong wants to ask.

Next q lines contain five integers x, y, a, b, and k each (1≤x,y,a,b≤n, x≠y, 1≤k≤109) – the integers explained in the description. It is guaranteed that the edge between x and y does not exist in the original tree.

Output
For each query, print “YES” if there exists a path that contains exactly k edges from vertex a to b after adding an edge between vertices x and y. Otherwise, print “NO”.

You can print each letter in any case (upper or lower).

Example

inputCopy
5
1 2
2 3
3 4
4 5
5
1 3 1 2 2
1 4 1 3 2
1 4 1 3 3
4 2 3 3 9
5 2 3 3 9
outputCopy
YES
YES
NO
YES
NO
Note
The image below describes the tree (circles and solid lines) and the added edges for each query (dotted lines).
在這裏插入圖片描述

Possible paths for the queries with “YES” answers are:

1-st query: 1 – 3 – 2
2-nd query: 1 – 2 – 3
4-th query: 3 – 4 – 2 – 3 – 4 – 2 – 3 – 4 – 2 – 3

題意:
給你一顆邊權爲1的樹,對於每個詢問,每次添加一條邊,再給你兩個點,詢問兩點之間經過的路徑長度是否等於k,兩點間的路徑可以多次包含相同點,相同邊,可以來回走

解析:
有一個性質
假設(a,b)路徑長度爲x,那麼x<=k 且x和k同奇偶性 才能輸出YES
簡單證明一下:
a,i,j,…k,b a到b的路徑上有i,j…k 。
路徑長度爲x,因爲可以來回走 b可以走到k,k可以走到b,重複下去 那麼走的次數肯定是2的倍數
那麼就相當於 x+2i 只有x+2i和k同奇偶性,才能走到。

那麼所有的路徑都是由3種路徑演變而來

第一種:a->b
第二種:a->x x->y y->b
第二種:a->y y->x x->b

又因爲 路徑長度x<=k 我們儘量給x取最小, 那麼我們可以用LCA去求解

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1000;
int fa[N][20]; 
int x,y,a,b,k;
int n,m;
int h[N],e[N*2],ne[N*2],idx;
int depth[N];
void add(int a,int b)
{
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int root)
{
	memset(depth,0x3f,sizeof depth);
	depth[0]=0;depth[root]=1;
	queue<int> q;
	q.push(root);
	while(q.size())
	{
		int t=q.front();
		q.pop();
		for(int i=h[t];~i;i=ne[i])
		{
			int j=e[i];
			if(depth[j]>depth[t]+1)
			{
				depth[j]=depth[t]+1;
				q.push(j);
				fa[j][0]=t;
				for(int k=1;k<=18;k++) fa[j][k]=fa[fa[j][k-1]][k-1]; 
			}
		}
	}
	
}
int lca(int x,int y)
{
	if(depth[x]<depth[y]) swap(x,y);
	for(int k=18;k>=0;k--) if(depth[fa[x][k]]>=depth[y]) x=fa[x][k];
	if(x==y) return x;
	for(int k=18;k>=0;k--) 
	{
		if(fa[x][k]!=fa[y][k])
		{
			x=fa[x][k];
			y=fa[y][k];
		}
	}
	return fa[x][0];
}
int getdis(int x,int y)
{
	return depth[x]+depth[y]-2*depth[lca(x,y)];
}
bool check(int x,int k)
{
	if(x<=k&&x%2==k%2) return 1;
	return 0;
}
int main()
{
	scanf("%d",&n);
	memset(h,-1,sizeof h);
	for(int i=0;i<n-1;i++)
	{
		cin>>a>>b;
		add(a,b);add(b,a);
	}
	dfs(1);
	scanf("%d",&m);
	while(m--)
	{
		cin>>x>>y>>a>>b>>k;
		if(check(getdis(a,b),k)||check(getdis(a,x)+getdis(y,b)+1,k)||check(getdis(a,y)+getdis(x,b)+1,k)) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
		
	}
 } 
發佈了430 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章