Skip to content

Commit ae01853

Browse files
lrvideckisweb-flow
andauthored
Linear kth par nit (#150)
* switch test * [auto-verifier] verify commit c139baa * add changes * [auto-verifier] verify commit d3d4c46 * speed up test * [auto-verifier] verify commit a7b7c0f * convert back to vector * [auto-verifier] verify commit ffd205e * [auto-verifier] verify commit 738bbf1 * final golf * adding git ignore to try to fix CI * final nits * [auto-verifier] remove .verify-helper/.gitignore (see online-judge-tools/verification-helper#332) * nit --------- Co-authored-by: GitHub <[email protected]>
1 parent 1b8ea7e commit ae01853

File tree

4 files changed

+55
-98
lines changed

4 files changed

+55
-98
lines changed

library/trees/ladder_decomposition/linear_kth_par.hpp

Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,47 @@
77
//! }
88
//! vector<basic_string<int>> adj(n);
99
//! linear_kth_par kp(adj);
10-
//! int kth_par = kp.kth_par(v, k);
10+
//! kp.kth_par(v, k); // k edges up from v
11+
//! kp.kth_par(v, 1); // v's parent
1112
//! @endcode
12-
//! kth_par = a node k edges up from v
13-
//! @time O(n + q)
14-
//! @space O(n)
15-
struct linear_kth_par {
16-
struct node {
17-
int d, p = -1, dl, idx_j;
18-
basic_string<int> lad;
19-
};
20-
vector<node> t;
21-
vector<pii> j;
13+
//! @time O(n*max((2*KAPPA+3)/KAPPA,2*KAPPA) + q)
14+
//! @space O(n*max((2*KAPPA+3)/KAPPA,2*KAPPA))
15+
template<int KAPPA = 2> struct linear_kth_par {
16+
int n;
17+
vi d, leaf, pos, jmp;
18+
vector<vi> lad;
2219
linear_kth_par(const auto& adj):
23-
t(sz(adj)), j(2 * sz(t)) {
24-
vi st;
25-
int pos = 1;
26-
auto add_j = [&]() -> void {
27-
j[pos] = {
28-
st[max<int>(0, sz(st) - 1 - 2 * (pos & -pos))],
29-
st[max<int>(0, sz(st) - 1 - 4 * (pos & -pos))]};
30-
pos++;
20+
n(sz(adj)), d(n), leaf(n), pos(n), jmp(2 * n), lad(n) {
21+
static_assert(KAPPA >= 1);
22+
int t = 1;
23+
vi st(n);
24+
auto calc = [&](int siz) {
25+
jmp[t] = st[max(0, siz - KAPPA * (t & -t))];
26+
t++;
3127
};
32-
auto dfs = [&](auto&& self, int v) -> void {
33-
st.push_back(v);
34-
t[v].idx_j = pos, t[v].dl = v;
35-
add_j();
28+
auto dfs = [&](auto&& self, int v, int p) {
29+
st[d[v]] = v;
30+
int& l = leaf[v] = v;
31+
pos[v] = t;
32+
calc(d[v]);
3633
for (int u : adj[v])
37-
if (u != t[v].p) {
38-
t[u].d = t[t[u].p = v].d + 1;
39-
self(self, u);
40-
if (t[t[u].dl].d > t[t[v].dl].d)
41-
t[v].dl = t[u].dl;
42-
add_j();
34+
if (u != p) {
35+
d[u] = 1 + d[v];
36+
self(self, u, v);
37+
if (d[l] < d[leaf[u]]) l = leaf[u];
38+
calc(d[v]);
4339
}
44-
st.pop_back();
40+
int s = (d[l] - d[v]) * (2 * KAPPA + 3) / KAPPA;
41+
s = min(max(s, 2 * KAPPA), d[l] + 1);
42+
rep(i, sz(lad[l]), s) lad[l].push_back(st[d[l] - i]);
4543
};
46-
rep(i, 0, sz(t)) {
47-
if (t[i].p == -1) dfs(dfs, i);
48-
if (t[i].p == -1 || t[t[i].p].dl != t[i].dl) {
49-
int v = t[i].dl, len = (t[v].d - t[i].d) * 2;
50-
auto& lad = t[v].lad;
51-
for (; v != -1 && len--; v = t[v].p) lad += v;
52-
}
53-
}
44+
dfs(dfs, 0, 0);
5445
}
5546
int kth_par(int v, int k) {
56-
assert(0 <= k && k <= t[v].d);
57-
switch (k) {
58-
case 0: return v;
59-
case 1: return t[v].p;
60-
case 2: return t[t[v].p].p;
61-
default:
62-
int i = bit_floor(unsigned(k / 3));
63-
auto [j1, j2] = j[(t[v].idx_j & -i) | i];
64-
int leaf = t[t[v].d - t[j2].d <= k ? j2 : j1].dl;
65-
return t[leaf].lad[k + t[leaf].d - t[v].d];
66-
}
47+
assert(0 <= k && k <= d[v]);
48+
int j = v;
49+
if (unsigned b = k / (KAPPA + 1); b)
50+
b = bit_floor(b), j = jmp[(pos[v] & -b) | b];
51+
return j = leaf[j], lad[j][k + d[j] - d[v]];
6752
}
6853
};

library/trees/linear_kth_path.hpp

Lines changed: 0 additions & 25 deletions
This file was deleted.

tests/library_checker_aizu_tests/trees/kth_path_ladder.test.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@ int main() {
1616
}
1717
ladder ld(adj);
1818
assert(sz(ld.l_tbl) <= 2 * n - ld.d[0]);
19-
vector<vector<int>> adj_rooted(n + n);
20-
for (int i = 0; i < n; i++)
21-
if (ld.p[i] != i) {
22-
adj_rooted[ld.p[i]].push_back(i);
23-
adj_rooted[ld.p[i] + n].push_back(i + n);
24-
}
25-
ladder ld_rooted(adj_rooted);
26-
linear_kth_par lin_ld_rooted(adj_rooted);
2719
while (q--) {
2820
int u, v, k;
2921
cin >> u >> v >> k;
@@ -34,23 +26,10 @@ int main() {
3426
else if (k <= u_lca) {
3527
int res = ld.kth_par(u, k);
3628
assert(res == jmp(ld.b_tbl, u, k));
37-
assert(res == ld_rooted.kth_par(u, k));
38-
assert(res == ld_rooted.kth_par(u + n, k) - n);
39-
assert(res == lin_ld_rooted.kth_par(u, k));
40-
assert(res == lin_ld_rooted.kth_par(u + n, k) - n);
4129
cout << res << '\n';
4230
} else {
4331
int res = ld.kth_par(v, u_lca + v_lca - k);
4432
assert(res == jmp(ld.b_tbl, v, u_lca + v_lca - k));
45-
assert(
46-
res == ld_rooted.kth_par(v, u_lca + v_lca - k));
47-
assert(res ==
48-
ld_rooted.kth_par(v + n, u_lca + v_lca - k) - n);
49-
assert(res ==
50-
lin_ld_rooted.kth_par(v, u_lca + v_lca - k));
51-
assert(res ==
52-
lin_ld_rooted.kth_par(v + n, u_lca + v_lca - k) -
53-
n);
5433
cout << res << '\n';
5534
}
5635
}

tests/library_checker_aizu_tests/trees/kth_path_linear.test.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#define PROBLEM \
22
"https://judge.yosupo.jp/problem/jump_on_tree"
33
#include "../template.hpp"
4-
#include "../../../library/trees/linear_kth_path.hpp"
4+
#include "../../../library/trees/linear_lca.hpp"
5+
#include "../../../library/trees/ladder_decomposition/linear_kth_par.hpp"
56
#include "../../../library/trees/lca_rmq/lca_rmq.hpp"
67
#include "../compress_tree_asserts.hpp"
78
int main() {
@@ -15,12 +16,29 @@ int main() {
1516
adj[u].push_back(v);
1617
adj[v].push_back(u);
1718
}
18-
linear_kth_path lin_kth_path(adj);
19+
linear_lca lin_lca(adj);
20+
linear_kth_par<1> lin_kp_1(adj);
21+
linear_kth_par<2> lin_kp_2(adj);
22+
linear_kth_par<3> lin_kp_3(adj);
23+
linear_kth_par<4> lin_kp_4(adj);
1924
LCA lc(adj);
2025
compress_tree_asserts(adj, lc);
26+
auto get_kth_par = [&](int v, int k) -> int {
27+
int res = lin_kp_1.kth_par(v, k);
28+
assert(res == lin_kp_2.kth_par(v, k));
29+
assert(res == lin_kp_3.kth_par(v, k));
30+
assert(res == lin_kp_4.kth_par(v, k));
31+
return res;
32+
};
2133
while (q--) {
2234
int u, v, k;
2335
cin >> u >> v >> k;
24-
cout << lin_kth_path.kth_path(u, v, k) << '\n';
36+
int lca_d = lin_kp_2.d[lin_lca.lca(u, v)];
37+
int u_lca = lin_kp_2.d[u] - lca_d;
38+
int v_lca = lin_kp_2.d[v] - lca_d;
39+
if (k <= u_lca) cout << get_kth_par(u, k) << '\n';
40+
else if (k <= u_lca + v_lca)
41+
cout << get_kth_par(v, u_lca + v_lca - k) << '\n';
42+
else cout << -1 << '\n';
2543
}
2644
}

0 commit comments

Comments
 (0)