牛客 城市网络
题意
给一棵 n n n 个点的树,每个节点代表一个城市,每个城市卖价值为 a i a_i ai 的珠宝,有 q q q 次询问,每次询问从 u u u 城市到 v v v 城市,一开始有价值为 c c c 的珠宝,如果当前经过的城市珠宝价值大于已有的所有珠宝的最大价值,就购买。保证 v v v 在 u u u 到根的路径上。问这次行程有几次购买。
题解
-
一次次的跳转到自己的父亲显然时间复杂度过大,所以考虑倍增跳转;
-
对于每次询问,在 u u u 的下方连一个虚拟的城市,城市卖价值为 c c c 的珠宝;
-
用 f [ u ] [ i ] f[u][i] f[u][i] 表示编号为 u u u 的城市出发第 2 i 2^i 2i 次购买在哪个城市;
-
i i i 从 1 1 1 开始可以使用类似求lca的方法进行转移,那么需要找到 f [ u ] [ 0 ] f[u][0] f[u][0] ;
-
求 f [ u ] [ 0 ] f[u][0] f[u][0] 也是倍增跳转, a [ f [ u ] [ i ] ] a[f[u][i]] a[f[u][i]] 是关于 i i i 递增的, x x x 是 u u u 的父亲城市, i i i 从大到小枚举,如果 a [ f [ x ] [ i ] ] < a [ u ] a[f[x][i]]<a[u] a[f[x][i]]<a[u] ,说明需要跳转的位置还在上面,先转移再继续循环判断;
-
询问的时候根据深度来判断即可,倍增跳转即可。
代码
#pragma region
//#pragma optimize("Ofast")
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 2e5 + 5;
int n, q;
vector<int> g[maxn];
int a[maxn], to[maxn];
int fa[maxn][20], dep[maxn];
void dfs(int u, int f) {
dep[u] = dep[f] + 1;
int x = f;
for (int i = 19; i >= 0; --i) {
if (!fa[x][i]) continue;
if (a[fa[x][i]] <= a[u]) x = fa[x][i];
}
fa[u][0] = (a[x] > a[u] ? x : fa[x][0]);
for (int i = 1; (1 << i) <= dep[u]; ++i)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (auto v : g[u]) {
if (v == f) continue;
dfs(v, u);
}
}
int query(int id) {
int ans = 0, x = id + n;
for (int i = 19; i >= 0; --i) {
if (dep[fa[x][i]] >= dep[to[id]]) {
ans += (1 << i);
x = fa[x][i];
}
}
return ans;
}
int main() {
scanf("%d%d", &n, &q);
rep(i, 1, n) scanf("%d", &a[i]);
rep(i, 1, n - 1) {
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
rep(i, n + 1, n + q) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
g[i].push_back(u);
g[u].push_back(i);
a[i] = c;
to[i - n] = v;
}
dfs(1, 0);
rep(i, 1, q) printf("%d\n", query(i));
}