>Link
ybtoj城市网络
>Description
有一个树状的城市网络(即 N N N 个城市由 N − 1 N-1 N−1 条道路连接的连通图),首都为 1 1 1 号城市,每个城市售卖价值为 a i a_i ai 的珠宝。
你是一个珠宝商,现在安排有 q q q 次行程,每次行程为从 u u u 号城市前往 v v v 号城市(走最短路径),保证 v v v 在 u u u 前往首都的最短路径上。
在每次行程开始时,你手上有价值为 c c c 的珠宝(每次行程可能不同),并且每经过一个城市时(包括 u u u 和 v v v ),假如那个城市中售卖的珠宝比你现在手上的每一种珠宝都要优秀(价值更高,即严格大于),那么你就会选择购入。
现在你想要对每一次行程,求出会进行多少次购买事件。
n , q ≤ 1 0 5 n,q\le10^5 n,q≤105
>解题思路
考虑从一个节点往上倍增,
g
i
,
j
g_{i,j}
gi,j 表示从
i
i
i 节点往上购买
2
j
2^j
2j 次到达的节点,如果我们知道了
g
i
,
0
g_{i,0}
gi,0 就可以求出所有了(倍增的精髓)
显然
g
i
,
0
g_{i,0}
gi,0 就是求
i
i
i 节点从下往上第一个大于
a
i
a_i
ai 的节点,这也可以用倍增来完成,用一个
m
a
x
n
i
,
j
maxn_{i,j}
maxni,j 来维护从
i
i
i 节点往上
2
j
2^j
2j 步这中间的最大值
然后对于每个询问,我们从
u
u
u 不断往上跳
g
g
g,注意不要超过
v
v
v,累计答案就好了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
struct edge
{
int to, nxt;
} e[N * 2];
int n, q, a[N], cnt, h[N], dep[N], fa[N][50], maxn[N][50], g[N][50];
void add (int u, int v)
{
e[++cnt] = (edge){v, h[u]}; h[u] = cnt;
e[++cnt] = (edge){u, h[v]}; h[v] = cnt;
}
void dfs (int now, int fath)
{
dep[now] = dep[fath] + 1;
fa[now][0] = fath;
maxn[now][0] = max (a[now], a[fath]);
for (int i = 1; i <= 20; i++)
{
fa[now][i] = fa[fa[now][i - 1]][i - 1];
maxn[now][i] = max (maxn[now][i - 1], maxn[fa[now][i - 1]][i - 1]);
}
int x = now;
for (int i = 20; i >= 0; i--)
if (maxn[x][i] <= a[now]) x = fa[x][i];
g[now][0] = fa[x][0];
for (int i = 1; i <= 20; i++)
g[now][i] = g[g[now][i - 1]][i - 1];
for (int i = h[now]; i; i = e[i].nxt)
if (e[i].to != fath) dfs (e[i].to, now);
}
int ask (int x, int y, int c)
{
int ret = 0;
if (a[x] <= c)
{
for (int i = 20; i >= 0; i--)
if (maxn[x][i] <= c) x = fa[x][i];
x = fa[x][0];
}
if (!x || dep[x] < dep[y]) return 0;
ret = 1;
for (int i = 20; i >= 0; i--)
if (g[x][i] && dep[g[x][i]] >= dep[y])
ret += 1 << i, x = g[x][i];
return ret;
}
int main()
{
freopen ("network.in", "r", stdin);
freopen ("network.out", "w", stdout);
int x, y, c;
scanf ("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf ("%d", &a[i]);
for (int i = 1; i < n; i++)
{
scanf ("%d%d", &x, &y);
add (x, y);
}
dfs (1, 0);
while (q--)
{
scanf ("%d%d%d", &x, &y, &c);
printf ("%d\n", ask (x, y, c));
}
return 0;
}