【题解】HackerRank-Neighborhood Queries

题目

https://www.hackerrank.com/contests/w38/challenges/neighborhood-queries

题意

给一棵带点权的树,每次询问距离一个点 $u$ 距离不超过 $d$ 的所有点的点权中第 $k$ 大的点权。

题解

  • 离线,点权离散化。
  • 建立点分树。
  • 在每棵点分树上按照权值从小到大依次插入主席树。
  • 问题转化成了在若干个主席树减去若干个主席树所形成的集合里询问第 k 大,这个就和树套树中主席树的查询一样了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)
#ifdef zerol
#define dbg(args...) do { cout << "\033[32;1m" << #args << " -> "; err(args); } while (0)
#else
#define dbg(...)
#endif
void err() { cout << "\033[39;0m" << endl; }
template<template<typename...> class T, typename t, typename... Args>
void err(T<t> a, Args... args) { for (auto x: a) cout << x << ' '; err(args...); }
template<typename T, typename... Args>
void err(T a, Args... args) { cout << a << ' '; err(args...); }
// -----------------------------------------------------------------------------
const int N = 5E4 + 10, INF = 1E9 + 1;
int w[N];

struct E {
int to, d;
};
vector<int> G[N];

bool vis[N];
int sz[N];
int get_sz(int u, int fa) {
int& s = sz[u] = 1;
for (int& v: G[u]) {
if (vis[v] || v == fa) continue;
s += get_sz(v, u);
}
return s;
}

void get_rt(int u, int fa, int s, int& m, int& rt) {
int t = s - sz[u];
for (int& v: G[u]) {
if (vis[v] || v == fa) continue;
get_rt(v, u, s, m, rt);
t = max(t, sz[v]);
}
if (t < m) { m = t; rt = u; }
}

int dep[N];
void get_dep(int u, int fa, int d) {
dep[u] = d;
for (int& v: G[u]) {
if (vis[v] || v == fa) continue;
get_dep(v, u, d + 1);
}
}

struct P {
int w;
int d, trt;
};
bool operator < (const P& a, const P& b) { return a.d < b.d; }
using VP = vector<P>;
struct R {
VP *rt, *rt2;
int dep;
};
VP pool[N << 1], *pit = pool;
vector<R> tr[N];

void go(int u, int fa, VP* rt, VP* rt2) {
tr[u].push_back({rt, rt2, dep[u]});
for (int& v: G[u]) {
if (v == fa || vis[v]) continue;
go(v, u, rt, rt2);
}
}

void dfs(int u) {
int tmp = INF; get_rt(u, -1, get_sz(u, -1), tmp, u);
vis[u] = true;
get_dep(u, -1, 0);
VP* rt = pit++; tr[u].push_back({rt, nullptr, 0});
for (int& v: G[u]) {
if (vis[v]) continue;
go(v, u, rt, pit++);
dfs(v);
}
}

typedef vector<int> VI;
struct TREE {
#define mid ((l + r) >> 1)
#define lson l, mid
#define rson mid + 1, r
static const int MAGIC = 750 * N;
struct P {
int w, ls, rs;
} tr[MAGIC];
int sz = 1;
TREE() { tr[0] = {0, 0, 0}; }
int New(int w, int ls, int rs) {
assert(sz < MAGIC - 1);
tr[sz] = {w, ls, rs};
return sz++;
}
int add(int tt, int l, int r, int x, int d) {
if (x < l || r < x) return tt;
const P& t = tr[tt];
if (l == r) return New(t.w + d, 0, 0);
return New(t.w + d, add(t.ls, lson, x, d), add(t.rs, rson, x, d));
}
int ls_sum(const VI& rt) {
int ret = 0;
FOR (i, 0, rt.size())
ret += tr[tr[rt[i]].ls].w;
return ret;
}
inline void ls(VI& rt) { for (int& x: rt) x = tr[x].ls; }
inline void rs(VI& rt) { for (int& x: rt) x = tr[x].rs; }
int query(VI& p, VI& q, int l, int r, int k) {
if (l == r) return l;
int w = ls_sum(q) - ls_sum(p);
if (k <= w) {
ls(p); ls(q);
return query(p, q, lson, k);
}
else {
rs(p); rs(q);
return query(p, q, rson, k - w);
}
}
} tree;

inline int get_trt(VP& x, int v) {
return (--upper_bound(x.begin(), x.end(), P{-1, v, -1}))->trt;
}

vector<int> tt;

int main() {
#ifdef zerol
freopen("in", "r", stdin);
#endif
int n; cin >> n;
FOR (i, 1, n + 1) {
scanf("%d", &w[i]);
tt.push_back(w[i]);
}
sort(tt.begin(), tt.end());
tt.erase(unique(tt.begin(), tt.end()), tt.end());
FOR (i, 1, n + 1) w[i] = lower_bound(tt.begin(), tt.end(), w[i]) - tt.begin() + 1;
FOR (_, 1, n) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v); G[v].push_back(u);
}
dfs(1);
FOR (i, 1, n + 1)
for (R& x: tr[i]) {
x.rt->push_back({w[i], x.dep, -1});
if (x.rt2) x.rt2->push_back({w[i], x.dep, -1});
}
FOR (it, pool, pit) {
it->push_back({0, -1, 0});
sort(it->begin(), it->end());
FOR (i, 1, it->size()) {
VP &x = *it;
x[i].trt = tree.add(x[i - 1].trt, 1, N, x[i].w, 1);
}
}
int Qn; cin >> Qn;
VI q, p;
while (Qn--) {
int u, d, k; scanf("%d%d%d", &u, &d, &k);
q.clear(); p.clear();
for (R& x: tr[u]) {
if (d - x.dep < 0) continue;
q.push_back(get_trt(*x.rt, d - x.dep));
if (x.rt2) p.push_back(get_trt(*x.rt2, d - x.dep));
}
int ans = tree.query(p, q, 1, N, k);
printf("%d\n", ans == N ? -1 : tt[ans - 1]);
}
}