題目鏈接:https://codeforces.com/contest/1304/problem/E
題意:給你一顆樹,多次詢問,每次給你一條連邊x,y的機會,問你a到b是否存在k條邊的路
其中某些邊可以重複任意次
思路;不加邊時只要k>= dis(a, b) 並且奇偶性相同就行,因爲邊可以重複走,考慮加邊時
帶來的影響是多了dis(a, x) + dis(y, b) + 1, dis(a, y) + dis(x, b) + 1這兩條路,判斷一下就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define ls rt << 1
#define rs rt << 1|1
#define po pop_back
#define pb push_back
#define mk make_pair
#define lson l, mid, ls
#define rson mid + 1, r, rs
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ull unsigned long long
#define pdd pair<double, double>
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
//head[u] 和 tot的初始值都爲-1
int head[maxn << 1], nxt[maxn << 1], to[maxn << 1], ver[maxn << 1];
int f[maxn][22], d[maxn], dis[maxn]; //d[x]表示x的深度, dis[y]表示y到根的距離
int n, m, s, lg, tot = -1;
queue<int> q;
void add(int u, int v, int w)
{
nxt[++tot] = head[u]; //當前邊的後繼
head[u] = tot; //起點u的第一條邊
to[tot] = v; //當前邊的終點
ver[tot] = w; //當前邊的權值
}
void bfs(int s)
{
while(!q.empty()) q.pop();
q.push(s), d[s] = 1;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = nxt[i])
{
int v = to[i];
if(d[v]) continue;
d[v] = d[u] + 1;
dis[v] = dis[u] + ver[i];
f[v][0] = u;
for(int j = 1; j <= lg; ++j)
f[v][j] = f[f[v][j - 1]][j - 1];
q.push(v);
}
}
}
int LCA(int u, int v)
{
if(d[u] > d[v]) swap(u, v);
for(int i = lg; i >= 0; --i) //u是v的祖先的情況
{
if(d[f[v][i]] >= d[u]) //不在同一條鏈上就處理到深度相同
v = f[v][i];
}
if(u == v) return u;
for(int i = lg; i >= 0; --i) //深度相同就可以同時倍增求
{
if(f[u][i] != f[v][i])
u = f[u][i], v = f[v][i];
}
return f[u][0];
}
int calc(int x, int y)
{
return d[x] + d[y] - 2 * d[LCA(x, y)];
}
bool check(int k, int d)
{
if(k >= d && k % 2 == d % 2) return 1;
return 0;
}
int main()
{
scanf("%d", &n);
lg = (int)(log(n) / log(2)) + 1; //枚舉的深度
for(int i = 0; i <= n; ++i) head[i] = -1, d[i] = 0;
tot = -1;
for(int i = 1; i < n; ++i)
{
int u, v, w = 1;
scanf("%d%d", &u, &v);
add(u, v, w), add(v, u, w);
}
bfs(1); //s是根節點
scanf("%d", &m);
while(m--)
{
int x, y, a, b, k;
scanf("%d%d%d%d%d", &x, &y, &a, &b, &k);
if(check(k, calc(a, b)) || check(k, calc(a, x) + calc(y, b) + 1) || check(k, calc(a, y) + calc(x, b) + 1))
printf("YES\n");
else printf("NO\n");
}
return 0;
}