hihocoder#1065 : 全图传送
[传送门]
如果只有单组询问就是水题。多组询问就不能直接在线做了。考虑离线。
点分治,把当前重心到未被处理过的子树的距离放进一个数组,按距离从小到大排序。排完序后把这些节点替换成当前前缀权值最大的节点。因为如果到这个节点的距离为$r$,那么小于$r$的也能到达,所以取前缀max没有错。
然后对询问的距离二分一下就可以了。
#include <bits/stdc++.h> #define pii pair<int, int> #define pb push_back #define fi first #define se second using namespace std; const int N = 1e5 + 7; int n, val[N], sz[N], maxsz[N], totsz, root; bool vis[N]; vector<pii> G[N]; struct QUE { int u, dis; QUE(int u = 0, int dis = 0): u(u), dis(dis) {} bool operator < (const QUE& t) const { return dis < t.dis; } } que[N]; int ans[N]; int ne[N], head[N], cnt, to[N]; void getroot(int u, int fa) { sz[u] = 1; maxsz[u] = 0; for (auto p: G[u]) { int v = p.se; if (vis[v] || v == fa) continue; getroot(v, u); sz[u] += sz[v]; maxsz[u] = max(maxsz[u], sz[v]); } maxsz[u] = max(maxsz[u], totsz - sz[u]); if (maxsz[u] < maxsz[root]) root = u; } QUE temp[N]; int tol, x[N]; void dfs(int u, int dep, int fa) { temp[++tol] = QUE(u, dep); for (auto p: G[u]) { int v = p.se; if (vis[v] || v == fa) continue; dfs(v, dep + p.fi, u); } } void cal() { sort(temp + 1, temp + 1 + tol); for (int i = 1; i <= tol; i++) { x[i] = temp[i].u; if (i == 1) continue; if (val[temp[i].u] < val[temp[i - 1].u] || (val[temp[i].u] == val[temp[i - 1].u] && temp[i].u > temp[i - 1].u)) temp[i].u = temp[i - 1].u; } for (int i = 1; i <= tol; i++) { for (int j = head[x[i]]; j; j = ne[j]) { QUE q = que[j]; if (q.dis < temp[i].dis) continue; int pos = upper_bound(temp + 1, temp + 1 + tol, QUE(0, q.dis - temp[i].dis)) - temp; if (pos <= tol && q.dis - temp[i].dis >= temp[pos].dis) pos++; pos--; if (val[ans[j]] < val[temp[pos].u] || (val[ans[j]] == val[temp[pos].u] && ans[j] > temp[pos].u)) ans[j] = temp[pos].u; } } } void solve(int u) { vis[u] = 1; tol = 0; dfs(u, 0, 0); cal(); for (auto p: G[u]) { int v = p.se; if (vis[v]) continue; totsz = sz[v]; root = 0; getroot(v, u); solve(root); } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &val[i]); for (int i = 1; i < n; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); G[u].pb(pii(w, v)); G[v].pb(pii(w, u)); } int q; scanf("%d", &q); for (int i = 1; i <= q; i++) { scanf("%d%d", &que[i].u, &que[i].dis); ne[++cnt] = head[que[i].u]; head[que[i].u] = cnt; ans[i] = n + 1; } maxsz[root = 0] = n; totsz = n; getroot(1, 0); solve(root); for (int i = 1; i <= q; i++) printf("%d\n", ans[i]); return 0; }