F.小Z的树迁移
思路
赛事没想出来如何做,可以发现,对于一个节点u,走d步所走的最远距离即为 深度为depthu+d且位于u的子树之中的节点距离根节点距离的最大值 再减去节点u距离根节点的距离即为结果
当我们查询时该如何做?
第一步,我们先给每个节点按照dfs序进行编号,这样保证了同一子树的节点的编号在\(l-r\)的一个连续区间内
第二步,把每个节点存进对应的深度容器中,当我们处理一个查询时,查询的深度即为depth[u]+d,我们找到对应深度容器,由于容器中满足条件的点为一段连续的区间,我们可以通过二分查询这段区间的首尾
第三步,预处理st表维护区间最大值
注意:处理二分边界条件
牛客官方题解
代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using piii = pair<int, pii>;
using pll = pair<ll, ll>;
using plll = pair<ll, pll>;
using plii = pair<ll, pii>;
#define fi first
#define se second
const int INF = 0x3f3f3f3f;
const ull mod1 = (1ull << 61) - 1, mod2 = 1e9 + 7;
const ull base1 = 131, base2 = 13331;
// mt19937 rnd(time(0));const int mod = 998244353;void solve() {int n;cin >> n;vector<vector<pii>> g(n + 1);for (int i = 1; i < n; i++) {int a, b, w;cin >> a >> b >> w;g[a].push_back({b, w}), g[b].push_back({a, w});}vector<int> depth(n + 1), siz(n + 1);vector<vector<pair<int, ll>>> tups(n + 1);vector<ll> dist(n + 1), dfn(n + 1);int cnt = 0;auto dfs = [&](auto&& self, int u, int fa) -> void {dfn[u] = ++cnt;depth[u] = depth[fa] + 1;siz[u] = 1;for (auto [y, w] : g[u]) {if (y == fa)continue;dist[y] = dist[u] + w;self(self, y, u);siz[u] += siz[y];}};dfs(dfs, 1, 0);for (int i = 1; i <= n; i++) {tups[depth[i]].push_back({dfn[i], dist[i]});}for (int i = 1; i <= n; i++) {auto& v = tups[i];sort(v.begin(), v.end());}vector<vector<vector<ll>>> sts(n + 1);for (int i = 1; i <= n; i++) {int len = tups[i].size();auto& v = sts[i];auto& data = tups[i];if (len) {int flen = log2(len) + 1;v.resize(len);for (int j = 0; j < len; j++)v[j].resize(flen);for (int j = 0; j < flen; j++) {for (int k = 0; k + (1 << j) - 1 < len; k++) {if (j == 0)v[k][j] = data[k].se;else {v[k][j] = max(v[k][j - 1], v[k + (1 << j - 1)][j - 1]);}}}}}auto get = [&](int l, int r, int dep) {auto& v = sts[dep];int k = log2(r - l + 1);// cout<<l<<" "<<r<<" "<<v.size()<<" "<<dep<<" "<<k<<endl;// cout<<v[0].size()<<endl;return max(v[l][k], v[r - (1 << k) + 1][k]);};int q;cin >> q;while (q--) {int u, d;cin >> u >> d;int dep = depth[u] + d;if (dep > n) {cout << -1 << endl;continue;}int bg = dfn[u], ed = dfn[u] + siz[u] - 1;auto& v = tups[dep];if (v.size() == 0) {cout << -1 << endl;continue;}int l1 = 0, r1 = v.size() - 1;while (l1 < r1) {int mid = l1 + r1 >> 1;if (v[mid].fi >= bg)r1 = mid;elsel1 = mid + 1;}int l2 = 0, r2 = v.size() - 1;while (l2 < r2) {int mid = l2 + r2 + 1 >> 1;if (v[mid].fi <= ed)l2 = mid;elser2 = mid - 1;}if (l2 < l1) {cout << -1 << endl;continue;}auto tt = v.front().fi;if (v.size() == 1 && (tt < bg || tt > ed)) {cout << -1 << endl;continue;}cout << get(l1, l2, dep) - dist[u] << endl;}
}int main() {cin.tie(nullptr);ios::sync_with_stdio(false);int _ = 1;// cin >> _;while (_--) {solve();}return 0;
}