|
1 | 1 | #pragma once |
2 | | -#include <cstdlib> |
| 2 | +#include <cassert> |
3 | 3 | #include <vector> |
4 | 4 |
|
5 | | -// CUT begin |
6 | 5 | // Binary lifting / `Doubling` |
7 | 6 | // Complexity: O(NlogN) precalculation / O(logN) per query |
8 | | -// <https://atcoder.jp/contests/arc060/submissions/7039451> |
| 7 | +// https://atcoder.jp/contests/arc060/submissions/7039451 |
9 | 8 | struct BinaryLifting { |
10 | | - int N, INVALID, lgD; |
| 9 | + int N, lgD; |
| 10 | + |
| 11 | + bool is_valid(int idx) const { return 0 <= idx and idx < N; } |
| 12 | + |
11 | 13 | std::vector<std::vector<int>> mat; |
12 | 14 | BinaryLifting() : N(0), lgD(0) {} |
13 | | - BinaryLifting(const std::vector<int> &vec_nxt, int INVALID = -1, int lgd = 0) |
14 | | - : N(vec_nxt.size()), INVALID(INVALID), lgD(lgd) { |
| 15 | + BinaryLifting(const std::vector<int> &to, int lgd = 0) : N(to.size()), lgD(lgd) { |
15 | 16 | while ((1LL << lgD) < N) lgD++; |
16 | | - mat.assign(lgD, std::vector<int>(N, INVALID)); |
17 | | - mat[0] = vec_nxt; |
18 | | - for (int i = 0; i < N; i++) |
19 | | - if (mat[0][i] < 0 or mat[0][i] >= N) mat[0][i] = INVALID; |
| 17 | + mat.assign(lgD, std::vector<int>(N)); |
| 18 | + mat[0] = to; |
| 19 | + |
20 | 20 | for (int d = 0; d < lgD - 1; d++) { |
21 | | - for (int i = 0; i < N; i++) |
22 | | - if (mat[d][i] != INVALID) mat[d + 1][i] = mat[d][mat[d][i]]; |
| 21 | + for (int i = 0; i < N; i++) { |
| 22 | + mat[d + 1][i] = mat[d][is_valid(mat[d][i]) ? mat[d][i] : i]; |
| 23 | + } |
23 | 24 | } |
24 | 25 | } |
25 | | - int kth_next(int now, long long k) { |
26 | | - if (k >= (1LL << lgD)) exit(8); |
27 | | - for (int d = 0; k and now != INVALID; d++, k >>= 1) |
| 26 | + |
| 27 | + int kth_next(int now, long long k) const { |
| 28 | + assert(k >= 0); |
| 29 | + assert(k < (1LL << lgD)); |
| 30 | + for (int d = 0; k and is_valid(now); d++, k >>= 1) { |
28 | 31 | if (k & 1) now = mat[d][now]; |
| 32 | + } |
29 | 33 | return now; |
30 | 34 | } |
31 | 35 |
|
32 | 36 | // Distance from l to [r, \infty) |
33 | | - // Requirement: mat[0][i] > i for all i (monotone increasing) |
34 | | - int distance(int l, int r) { |
| 37 | + // Requirement: mat[0][i] >= r (i = r, r + 1, ...) (monotone) |
| 38 | + int distance(int l, int r) const { |
35 | 39 | if (l >= r) return 0; |
36 | 40 | int ret = 0; |
37 | 41 | for (int d = lgD - 1; d >= 0; d--) { |
38 | | - if (mat[d][l] < r and mat[d][l] != INVALID) ret += 1 << d, l = mat[d][l]; |
| 42 | + if (mat[d][l] < r and is_valid(mat[d][l])) ret += 1 << d, l = mat[d][l]; |
39 | 43 | } |
40 | | - if (mat[0][l] == INVALID or mat[0][l] >= r) |
| 44 | + |
| 45 | + if (!is_valid(mat[0][l]) or mat[0][l] >= r) { |
41 | 46 | return ret + 1; |
42 | | - else |
| 47 | + } else { |
43 | 48 | return -1; // Unable to reach |
| 49 | + } |
44 | 50 | } |
45 | 51 | }; |
0 commit comments