G. Vlad and the Mountains

发布时间 2023-08-11 16:02:25作者: onlyblues

G. Vlad and the Mountains

Vlad decided to go on a trip to the mountains. He plans to move between $n$ mountains, some of which are connected by roads. The $i$-th mountain has a height of $h_i$.

If there is a road between mountains $i$ and $j$, Vlad can move from mountain $i$ to mountain $j$ by spending $h_j - h_i$ units of energy. If his energy drops below zero during the transition, he will not be able to move from mountain $i$ to mountain $j$. Note that $h_j - h_i$ can be negative and then the energy will be restored.

Vlad wants to consider different route options, so he asks you to answer the following queries: is it possible to construct some route starting at mountain $a$ and ending at mountain $b$, given that he initially has $e$ units of energy?

Input

The first line of the input contains an integer $t$ ($1 \le t \le 10^4$) — the number of test cases.

The descriptions of the test cases follow.

The first line of each test case contains two numbers $n$ and $m$ ($2 \le n \le 2 \cdot 10^5$, $1 \le m \le \min(\frac{n\cdot(n - 1)}{2}, 2 \cdot 10^5)$) — the number of mountains and the number of roads between them, respectively.

The second line contains $n$ integers $h_1, h_2, h_3, \dots, h_n$ ($1 \le h_i \le 10^9$) — the heights of the mountains.

The next $m$ lines contain two integers $u$ and $v$ ($1 \le u, v \le n$, $u \ne v$) — the numbers of the mountains connected by a road. It is guaranteed that no road appears twice.

The next line contains an integer $q$ ($1 \le q \le 2 \cdot 10^5$) — the number of queries.

The following $q$ lines contain three numbers $a$, $b$, and $e$ ($1 \le a, b \le n$, $0 \le e \le 10^9$) — the initial and final mountains of the route, and the amount of energy, respectively.

It is guaranteed that the sum of $n$ over all test cases does not exceed $2 \cdot 10^5$. The same guarantee applies to $m$ and $q$.

Output

For each query, output "YES" if Vlad can construct a route from mountain $a$ to mountain $b$, and "NO" otherwise.

You can output the answer in any case (for example, the strings "yEs", "yes", "Yes", and "YES" will be recognized as a positive answer).

In the examples below, the answers for different test cases are separated by an empty line, which you do not need to output.

Examples

input

2
7 7
1 5 3 4 2 4 1
1 4
4 3
3 6
3 2
2 5
5 6
5 7
5
1 1 3
6 2 0
4 7 0
1 7 4
1 7 2
6 5
4 7 6 2 5 1
1 3
5 3
1 5
2 4
6 2
5
1 5 1
1 3 1
1 2 1000
6 2 6
6 2 5

output

YES
NO
YES
YES
NO

YES
NO
NO
YES
NO

input

2
3 2
1 3 9
1 2
2 3
5
1 1 1
3 2 2
1 1 2
3 3 0
1 2 1
3 3
1 4 1
1 2
2 3
1 3
5
3 3 9
1 3 6
1 1 2
3 3 6
3 3 4

output

YES
YES
YES
YES
NO

YES
YES
YES
YES
YES

input

1
6 10
7 9 2 10 8 6
4 2
6 1
4 5
3 5
6 4
1 3
2 6
6 5
1 2
3 6
5
4 4 8
3 3 1
5 5 9
2 1 7
6 6 10 

output

YES
YES
YES
YES
YES

 

解题思路

  首先要发现这样一个性质,对于路径$i \to j \to k$,消耗的能量为$h_j - h_i + h_k - h_j = h_k - h_i$,即从$i$到$k$的路径中消耗的能量只取决于起点和终点的高度。现在的问题是给定初始能力$e$,问是否存在一条从$a$到$b$的路径。很明显至少要满足$h_b - h_a \leq e$才可能存在从$a$到$b$的路径,即$h_b$要满足$h_b \leq h_a + e$。再考虑路径中经过的山脉高度,事实上只要路径中的所有点都满足$h_i \leq h_a + e$,那么就一定是一条从$a$到$b$的路径,因为这样就可以保证不会出现经过下一个点后能量小于$0$的情况。反证法,假设当前到达点$u$,消耗的能量是$h_u - h_a \leq e$,并且从$a$到$u$的过程中能量始终不低于$0$,如果从$u$到下一个点$v$消耗的能量超过到达$u$时剩余的能量,即$h_v - h_u + h_u - h_a > e$,即有$h_v - h_a > e$,这就与$h_v - h_a \leq e$矛盾了。

  因此如果给定起点$a$,终点$b$和初始能量$e$,将图中所有高度不超过$h_a + e$的点选择出来,若选出的某两个点存在边相连则将这两个点所在连通块进行合并,最后如果$a$和$b$在一个连通块,则说明存在一条从$a$到$b$的路径。如果直接枚举每个询问然后都按照上面的说法来做,那么时间复杂度就是$O(q(n+m))$,肯定会超时。可以发现对于每个询问我们每次都是找出小于某个值的点,因此可以离线处理询问,根据关键字$h[a[i]] + e[i]$从小到大枚举每个询问,并且依次把高度不超过$h[a[i]] + e[i]$的点加到连通块中,这样就大大减少了重复加入的过程。

  具体做法是对每个点按照高度$h_i$进行升序排序,同时对每个询问按照关键字$h[a[i]] + e[i]$进行升序排序。然后按照顺序依次枚举询问,用一个指针维护已加到哪个点,当枚举到排序后的第$i$个询问,那么就从指针开始往后枚举,把所有高度不超过$h[a[i]] + e[i]$的点都加到连通块中(即枚举与该点相连的所有边,若边的另一个端点的高度也不超过$h[a[i]] + e[i]$,这合并这两个点所在的连通块),最后看看$a_i$和$b_i$是否在同一个连通块。

  AC代码如下,时间复杂度为$O(m + n\log{n} + q\log{q})$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 2e5 + 10;
 7 
 8 int h[N], p[N];
 9 int a[N], b[N], c[N], q[N];
10 vector<int> g[N];
11 int fa[N];
12 bool ans[N];
13 
14 int find(int x) {
15     return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
16 }
17 
18 void solve() {
19     int n, m;
20     scanf("%d %d", &n, &m);
21     for (int i = 1; i <= n; i++) {
22         scanf("%d", h + i);
23         p[i] = i;
24         g[i].clear();
25     }
26     while (m--) {
27         int v, w;
28         scanf("%d %d", &v, &w);
29         g[v].push_back(w);
30         g[w].push_back(v);
31     }
32     scanf("%d", &m);
33     for (int i = 1; i <= m; i++) {
34         scanf("%d %d %d", a + i, b + i, c + i);
35         q[i] = i;
36     }
37     sort(p + 1, p + n + 1, [&](int i, int j) {    // 山脉按照高度从小到大排序 
38         return h[i] < h[j];
39     });
40     sort(q + 1, q + m + 1, [&](int i, int j) {    // 询问按照关键字h[a[i]]+c[i]从小到大排序 
41         return h[a[i]] + c[i] < h[a[j]] + c[j];
42     });
43     for (int i = 1; i <= n; i++) {
44         fa[i] = i;
45     }
46     memset(ans, 0, m + 10);
47     for (int i = 1, j = 1; i <= m; i++) {
48         while (j <= n && h[p[j]] <= h[a[q[i]]] + c[q[i]]) {    // 把所有高度不超过h[a[q[i]]]+c[q[i]]的点加到连通块中 
49             for (auto &x : g[p[j]]) {
50                 if (h[x] <= h[p[j]]) fa[find(x)] = find(p[j]);    // 边的另外一端的高度也要满足不超过h[a[q[i]]]+c[q[i]],因为此时连通块的点都不超过h[a[q[i]]]+c[q[i]] 
51             }
52             j++;
53         }
54         ans[q[i]] = find(a[q[i]]) == find(b[q[i]]);    // 查询起点和终点是否在同一个连通块中 
55     }
56     for (int i = 1; i <= m; i++) {
57         printf("%s\n", ans[i] ? "YES" : "NO");
58     }
59 }
60 
61 int main() {
62     int t;
63     scanf("%d", &t);
64     while (t--) {
65         solve();
66     }
67     
68     return 0;
69 }

 

参考资料

  Codeforces round #888 (Div. 3) Editorial:Codeforces round #888 (Div. 3) Editorial - Codeforces