题意:
一棵
n
n
个节点没条边权值是或者
2
2
的树,有个查询,每次给出
(x,y,z)
(
x
,
y
,
z
)
,问每次跳跃步数不超过
z
z
的情况下,最少跳几次能从跳到
y
y
。
思路:
当
z>n−−√
z
>
n
的时候暴力跳,知道这里不会超过
n−−√
n
步,否则预处理出树上的关键点,关键点是指:该点的深度
mod n−−√=0
m
o
d
n
=
0
的点,那么可以知道关键点之间的跳跃不会超过
n−−√
n
步,这样预处理每两个关键点在步数小于
n−−√
n
的时候从一个关键点到上一个关键点需要跳多少次,最终剩余多少步没跳完,这样查询
x
x
到得出最少跳的次数和最后剩余的步数,对
y
y
<script type="math/tex" id="MathJax-Element-2142">y</script>也是如此,处理两条链的情况就行了。细节很多。。。
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
using namespace std;
typedef pair<int, int> pa;
vector<pa> vec[maxn];
int anc[maxn][18], deep[maxn];
int n, m, dist[maxn], block_size = 350;
int sz[maxn], key[maxn], bel[maxn];
int can_arrive[maxn][352]; ///当前点步长为z的时候,下一步的位置
pa jump[maxn][352]; ///当前点跳到下一个关键点,步长为z的时候最少需要first步,到达关键点还剩余second单位长
void dfs(int x, int fa, int d, int ds, int tot_dis) {
anc[x][0] = fa; deep[x] = d;
dist[x] = tot_dis; sz[x] = 1;
for(int i = 1; i < 18; i++) {
int t = anc[x][i - 1];
if(~t) anc[x][i] = anc[t][i - 1];
else break;
}
for(int i = 0; i <= block_size; i++) {
if(i >= ds) can_arrive[x][i] = can_arrive[fa][i - ds];
else can_arrive[x][i] = x;
if(!can_arrive[x][i]) can_arrive[x][i] = 1;
}
for(int i = 0; i < vec[x].size(); i++) {
pa e = vec[x][i];
if(e.first != fa) dfs(e.first, x, d + 1, e.second, tot_dis + e.second);
if(e.first != fa) sz[x] += sz[e.first];
}
if(deep[x] % 175 == 0 && sz[x] >= 175) key[x] = 1;
}
int query_anc(int x, int y) {
if(deep[x] < deep[y]) swap(x, y);
for(int i = 17; i >= 0; i--) {
if(deep[x] - (1 << i) < deep[y]) continue;
x = anc[x][i];
}
if(x == y) return x;
for(int i = 17; i >= 0; i--) {
if(anc[x][i] == anc[y][i]) continue;
x = anc[x][i]; y = anc[y][i];
}
return anc[x][0];
}
void init_jump(int x, int fa, int im) {
bel[x] = im;
for(int i = 0; i <= block_size; i++) {
int tot_dis = dist[x] - dist[bel[x]]; ///跳下一个关键点
if(i >= tot_dis) {
jump[x][i].first = 1;
jump[x][i].second = i - tot_dis;
} else {
int nxt = can_arrive[x][i];
if(nxt == x) continue;
jump[x][i].first = jump[nxt][i].first + 1;
jump[x][i].second = jump[nxt][i].second;
}
}
for(int i = 0; i < vec[x].size(); i++) {
pa e = vec[x][i];
if(e.first == fa) continue;
if(key[x]) init_jump(e.first, x, x);
else init_jump(e.first, x, im);
}
}
void solve(int &x, int to, pa &now, int len) {
while(x != to) {
if(dist[x] - dist[anc[x][0]] > now.second) { now.second = len; now.first++; }
now.second -= dist[x] - dist[anc[x][0]];
x = anc[x][0];
}
}
pa jump_to_lca(int x, int lca, int len) {
pa now = pa(0, 0);
while(bel[x] != bel[lca]) {
int b = bel[x];
int tot_dis = dist[x] - dist[b]; ///当前点到关键点的距离
if(len >= block_size) { ///暴力跳
if(dist[x] - dist[b] > block_size) {
solve(x, b, now, len);
} else {
while(now.second < dist[x] - dist[b]) {
x = can_arrive[x][now.second];
now.second = len; now.first++;
}
now.second -= dist[x] - dist[b];
x = b;
}
} else {
if(deep[can_arrive[x][now.second]] < deep[lca]) break;
int tx = can_arrive[x][now.second];
now.second -= dist[x] - dist[tx];
x = tx;
if(bel[x] == b) {
now.first += jump[x][len].first;
now.second = jump[x][len].second;
x = b;
}
}
}
if(deep[x] >= deep[lca]) solve(x, lca, now, len);
else now.second = dist[lca] - dist[x];
return now;
}
int query(int x, int y, int z) {
int lca = query_anc(x, y);
pa info_x = jump_to_lca(x, lca, z);
pa info_y = jump_to_lca(y, lca, z);
if(info_x.second == z) { info_x.first--; info_x.second = 0; }
if(info_y.second == z) { info_y.first--; info_y.second = 0; }
if(!info_x.second || !info_y.second) return info_x.first + info_y.first;
int rx = info_x.second, ry = z - info_y.second;
if(rx >= ry) return info_x.first + info_y.first - 1;
else return info_x.first + info_y.first;
}
const int MAX = 10000;
char buf[MAX], *ps = buf, *pe = buf + 1;
inline void rnext() {
if(++ps == pe) pe = (ps = buf) + fread(buf, sizeof(char), sizeof(buf) / sizeof(char), stdin);
}
template <class T>
inline bool in(T &ans) {
ans = 0;
T f = 1;
if(ps == pe) return false;//EOF
do{
rnext();
if('-' == *ps) f = -1;
} while(!isdigit(*ps) && ps != pe);
if(ps == pe) return false;//EOF
do {
ans = (ans<<1)+(ans<<3)+*ps-48;
rnext();
} while(isdigit(*ps) && ps != pe);
ans *= f;
return true;
}
int main() {
in(n);
for(int i = 0; i < maxn; i++) vec[i].clear();
memset(anc, -1, sizeof anc);
for(int i = 0; i < n - 1; i++) {
int u, v, c;
in(u); in(v); in(c);
vec[u].push_back(pa(v, c));
vec[v].push_back(pa(u, c));
}
dfs(1, 0, 1, 0, 0);
key[1] = 1; bel[1] = 1;
init_jump(1, 0, 0);
in(m);
while(m--) {
int x, y, z;
in(x); in(y); in(z);
int ans = query(x, y, z);
printf("%d\n", ans);
}
return 0;
}