题目链接:https://codeforces.com/contest/1304/problem/E
题目大意:
给一棵树,q次询问,问在x和y中加一条边,a能否存在一条路径到达b,且长度恰好为k,一条边可以反复走。
题目思路:
如果没有加边这个条件的话,可以发现,如果从a到b,路径一定是a到b的最短距离+2*x,因为树上两点间的最短路是固定的,要是走了别的路还得回来一定得算两倍,所以唯一的变数就在于新加入的这条边,所以就再计算一下a先到x,然后走新边到达y,再从y到b行不行,最后再算一下a先到y,然后走新边到达x,再从x到b行不行,有一种行就行,否则就不行。
以下是代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int MAXN = 2e5+5;
const int MOD = 1e9+7;
int f[MAXN][20],d[MAXN],dist[MAXN];
int ver[MAXN],Next[MAXN],head[MAXN];
int n,u,v,t,T,tot;
queue<int>q;
void add(int x,int y){
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
void bfs(){
q.push(1);d[1]=1;
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(d[y])continue;
d[y]=d[x]+1;
dist[y]=dist[x]+1;
f[y][0]=x;
rep(j,1,t){
f[y][j]=f[f[y][j-1]][j-1];
}
q.push(y);
}
}
}
int lca(int x,int y){
if(d[x]>d[y])swap(x,y);
per(i,t,0){
if(d[f[y][i]]>=d[x])y=f[y][i];
}
if(x==y)return x;
per(i,t,0){
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
}
return f[x][0];
}
int dis(int x,int y){
int fa=lca(x,y);
return dist[x]+dist[y]-2*dist[fa];
}
int main()
{
while(cin>>n){
tot=0;
memset(head,0,sizeof(head));
rep(i,1,n-1){
cin>>u>>v;
add(u,v);
add(v,u);
}
t=(int)(log(n)/log(2))+1;
bfs();
cin>>T;
while(T--){
int x,y,a,b,k;
cin>>x>>y>>a>>b>>k;
int p=dis(a,b);
if(k>=p&&(k-p)%2==0){
cout<<"YES"<<endl;
continue;
}
p=dis(a,x)+1+dis(y,b);
if(k>=p&&(k-p)%2==0){
cout<<"YES"<<endl;
continue;
}
p=dis(a,y)+1+dis(x,b);
if(k>=p&&(k-p)%2==0){
cout<<"YES"<<endl;
continue;
}
cout<<"NO"<<endl;
}
}
return 0;
}