[Codeforces Round #620 (Div. 2)] E. 1-Trees and Queries
time limit per test
4 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
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 nn vertices, then he will ask you qq queries. Each query contains 55 integers: xx, yy, aa, bb, and kk. This means you're asked to determine if there exists a path from vertex aa to bb that contains exactly kk edges after adding a bidirectional edge between vertices xx and yy. 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 nn (3≤n≤1053≤n≤105), the number of vertices of the tree.
Next n−1n−1 lines contain two integers uu and vv (1≤u,v≤n1≤u,v≤n, u≠vu≠v) each, which means there is an edge between vertex uu and vv. All edges are bidirectional and distinct.
Next line contains an integer qq (1≤q≤1051≤q≤105), the number of queries Gildong wants to ask.
Next qq lines contain five integers xx, yy, aa, bb, and kk each (1≤x,y,a,b≤n1≤x,y,a,b≤n, x≠yx≠y, 1≤k≤1091≤k≤109) – the integers explained in the description. It is guaranteed that the edge between xx and yy does not exist in the original tree.
Output
For each query, print "YES" if there exists a path that contains exactly kk edges from vertex aa to bb after adding an edge between vertices xx and yy. Otherwise, print "NO".
You can print each letter in any case (upper or lower).
Example
input
Copy
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
output
Copy
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:
- 11-st query: 11 – 33 – 22
- 22-nd query: 11 – 22 – 33
- 44-th query: 33 – 44 – 22 – 33 – 44 – 22 – 33 – 44 – 22 – 33
题意:
给定一个含有n个节点的树,以及q个询问。
每一个询问给出5个整数,x,y,a,b,k
代表如果像树中的x节点和y节点之间加一条边,问是否纯在一条路径从a到b(可以同一个节点走多次)距离为k?
思路:
我们假设a到b的最短路径长度为L,显然对于任意一个非负整数z,满足存在一个a到b的路径长为(L+2*z)。
所以我们只需要判断是否存在一个路径距离为L,满足:$L leq k $,且L与K同奇偶性。
通过分析可以得知,对于每一个询问的a,b只有以下三个有意义的路径(即其他的路径可以通过这三条路径加(2*z)得到):
1、a到b的简单路径(不使用新增加的边)。
2、(a->x->y->b)
2、(a->y->x->b)
分别判断是否有一条路径符合:$L leq k $,且L与K同奇偶性 即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), ' ', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define N maxn
std::vector<int> son[N];
ll depth[N];
int fa[N][21], in[N], a, b;
int n;
int q;
void dfs(int rt, int prev)
{
depth[rt] = depth[prev] + 1;
fa[rt][0] = prev;
for (int i = 1; i < 20; i++)
{
fa[rt][i] = fa[fa[rt][i - 1]][i - 1];
}
for (int i = 0; i < son[rt].size(); i++)
{
if (son[rt][i] == prev)
continue;
dfs(son[rt][i], rt);
}
}
int LCA(int x, int y)
{
if (depth[x] < depth[y])
swap(x, y);
for (int i = 19; i >= 0; i--)
{
if (depth[x] - (1 << i) >= depth[y])
{
x = fa[x][i];
}
}
if (x == y)
{
return x;
}
for (int i = 19; i >= 0; i--)
{
if (fa[x][i] != fa[y][i])
{
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
ll dist(int a, int b)
{
int u = LCA(a, b);
ll L = depth[a] + depth[b] - 2ll * depth[u];
return L;
}
int main()
{
//freopen("D:\code\text\input.txt","r",stdin);
//freopen("D:\code\text\output.txt","w",stdout);
depth[0] = -1;
n = readint();
repd(i, 2, n)
{
a = readint();
b = readint();
son[a].push_back(b);
son[b].push_back(a);
}
dfs(1, 0);
q = readint();
int x, y;
ll k;
while (q--)
{
x = readint();
y = readint();
a = readint();
b = readint();
k = readll();
ll disab = dist(a, b);
ll disaxyb = dist(a, x) + 1 + dist(y, b);
ll disayxb = dist(a, y) + 1 + dist(x, b);
int isok = 0;
ll ans = inf;
if (disab % 2 == k % 2)
{
ans = min(ans, disab);
}
if (disaxyb % 2 == k % 2)
{
ans = min(ans, disaxyb);
}
if (disayxb % 2 == k % 2)
{
ans = min(ans, disayxb);
}
if (ans <= k)
{
isok = 1;
}
if (isok)
{
printf("YES
");
} else
{
printf("NO
");
}
}
return 0;
}