P11885 [RMI 2024] 跑酷 题解

Description

nn 个岛,编号 1n1\sim n。给定长度为 (n1)(n-1) 的正整数数列 v1,v2,,vn1v_1,v_2,\ldots,v_{n-1}

当你在岛 ii1i<n1\le i\lt n)上时,可以跳到岛 (i+1)(i+1) 上或者岛 viv_i 上。这里,i<vii\lt v_i

给定正整数 kk。对于岛 ii,定义 f(i,k)f(i,k) 表示从它出发跳至多 kk 步能够跳到的岛有多少个(包括自身)。

此外,viv_i 还满足特殊性质对于任意 1i<j<n1\le i\lt j\lt n,要么 vijv_i\le j,要么 vjviv_j\le v_i

对于 i=1,2,,ni=1,2,\ldots,n,求出 f(i,k)f(i,k)

补充说明:即使岛 ii 有多种在 kk 步内跳到岛 jj 的方式,岛 jj 也只算一次。

1n3×1051\le n\le 3\times 10^5

Solution

假设要从 ii 走到 jj,由于特殊性质的存在,如果 vijv_i\leq j 则一定走 viv_i,否则才走 i+1i+1

考虑对于起点 ii 从大到小枚举,同时用数据结构维护每个终点的距离 disjdis_j。容易发现对于 [i+1,vi1][i+1,v_i-1] 内的终点只需要加一,而由于 i+1i+1 走到 [vi,n][v_i,n] 必然会经过 viv_i,所以 [vi,n][v_i,n] 内的距离需要加 1disvi1-dis_{v_i}

于是问题转化为了:区间加,查询全局小于等于某个数的个数。

分块维护即可。

时间复杂度:O(nn)O(n\sqrt n)

Code(被卡常了)

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
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 3e5 + 5, kMaxB = 155, kMaxT = kMaxN / (kMaxB - 5) + 5;

int n, k, b, tot;
int a[kMaxN], f[kMaxN], ans[kMaxN];
int bel[kMaxN], L[kMaxT], R[kMaxT], val[kMaxN], cntu[kMaxT], tag[kMaxT], unq[kMaxT][kMaxB], cnt[kMaxT][kMaxB];
int pos[kMaxT];

void prework() {
// b = round(sqrtl(n * std::__lg(n)));
b = std::min(n, 150);
tot = (n + b - 1) / b;
for (int i = 1; i <= tot; ++i) {
L[i] = (i - 1) * b + 1, R[i] = std::min(i * b, n);
pos[i] = cntu[i] = 1, unq[i][1] = 0, cnt[i][1] = R[i] - L[i] + 1;
for (int j = L[i]; j <= R[i]; ++j)
bel[j] = i;
}
}

void rebuild(int x, int v) {
static int unq[kMaxN * 2], cnt[kMaxN * 2] = {0};
static int unq1[kMaxN * 2], unq2[kMaxN * 2] = {0};
static bool vis[kMaxN * 2];
int mm = cntu[x];
int m1 = 0, m2 = 0;
for (int i = L[x]; i <= R[x]; ++i) ++cnt[val[i] += tag[x]];
for (int i = 1; i <= mm; ++i) {
unq[i] = ::unq[x][i] + tag[x];
int vv = unq[i] + v;
if (!vis[unq[i]] && cnt[unq[i]]) unq1[++m1] = unq[i], vis[unq[i]] = 1;
if (vv >= 0 && !vis[vv] && cnt[vv]) unq2[++m2] = vv, vis[vv] = 1;
}
// for (int i = 1; i <= mm; ++i)
// if (unq[i] + v >= 0 && cnt[unq[i] + v] && !vis[unq[i] + v])
// unq2[++m2] = unq[i] + v;
// for (int i = 1; i <= m1; ++i) assert(cnt[unq1[i]]);
// for (int i = 1; i <= m2; ++i) assert(!vis[unq2[i]]);
// for (int i = 1; i <= mm; ++i) vis[unq[i]] = 0;
cntu[x] = tag[x] = 0;
for (int i = 1, j = 1; i <= m1 || j <= m2;) {
int v = 0;
if (i <= m1 && (j > m2 || unq1[i] < unq2[j])) v = unq1[i], ++i;
else v = unq2[j], ++j;
// assert(cnt[v]);
::unq[x][++cntu[x]] = v;
::cnt[x][cntu[x]] = ::cnt[x][cntu[x] - 1] + cnt[v];
vis[v] = cnt[v] = 0;
}
// for (int i = L[x]; i <= R[x]; ++i) assert(!cnt[val[i]]);
// int i = 1, j = 1;
// for (; j <= mm && unq[j] + v < 0; ++j) {}
// for (; i <= mm || j <= mm;) {
// for (; i <= mm && !cnt[unq[i]]; ++i) {}
// for (; j <= mm && !cnt[unq[j] + v]; ++j) {}
// int v1 = unq[i], v2 = unq[j] + v;
// if (i <= mm && (j > mm || v1 <= v2)) {
// ::unq[x][++cntu[x]] = v1;
// ::cnt[x][cntu[x]] = ::cnt[x][cntu[x] - 1] + cnt[v1];
// cnt[v1] = 0;
// } else if (v2 >= 0 && cnt[v2]) {
// ::unq[x][++cntu[x]] = v2;
// ::cnt[x][cntu[x]] = ::cnt[x][cntu[x] - 1] + cnt[v2];
// cnt[v2] = 0;
// }
// }
// int mm = 0;
// for (int i = L[x]; i <= R[x]; ++i) {
// ++cnt[val[i] += tag[x]];
// unq[++mm] = val[i];
// }
// std::sort(unq + 1, unq + 1 + mm);
// mm = std::unique(unq + 1, unq + 1 + mm) - (unq + 1);
// cntu[x] = mm, tag[x] = 0;
// for (int i = 1; i <= mm; ++i) {
// ::unq[x][i] = unq[i];
// ::cnt[x][i] = ::cnt[x][i - 1] + cnt[unq[i]];
// cnt[unq[i]] = 0;
// }
pos[x] = 0;
for (; pos[x] < cntu[x] && ::unq[x][pos[x] + 1] <= k; ++pos[x]) {}
// for (int i = L[x]; i <= R[x]; ++i) assert(!cnt[val[i]]);
}

void update(int l, int r, int v) {
if (l > r) return;
int x = bel[l], y = bel[r];
if (x == y) {
for (int i = l; i <= r; ++i) val[i] += v;
rebuild(x, v);
} else {
for (int i = x + 1; i < y; ++i) {
tag[i] += v;
for (; pos[i] < cntu[i] && unq[i][pos[i] + 1] + tag[i] <= k; ++pos[i]) {}
for (; pos[i] && unq[i][pos[i]] + tag[i] > k; --pos[i]) {}
}
for (int i = l; i <= R[x]; ++i) val[i] += v;
for (int i = L[y]; i <= r; ++i) val[i] += v;
rebuild(x, v), rebuild(y, v);
}
}

int query(int i) { return val[i] + tag[bel[i]]; }

int query(int l, int v) {
int ret = 0, x = bel[l];
// for (int i = l; i <= n; ++i) ret += (query(i) <= v);
for (int i = l; i <= R[x]; ++i) ret += (val[i] + tag[x] <= v);
// for (int i = x + 1; i <= tot; ++i) ret += cnt[i][std::upper_bound(unq[i] + 1, unq[i] + 1 + cntu[i], v - tag[i]) - unq[i] - 1];
for (int i = x + 1; i <= tot; ++i) ret += cnt[i][pos[i]];
return ret;
}

void dickdreamer() {
std::cin >> n >> k;
for (int i = 1; i < n; ++i) std::cin >> a[i];
a[n] = n + 1;
std::fill_n(f + 1, n, k + 1);
prework();
for (int i = n; i; --i) {
// f[i] = 0;
// for (int j = i + 1; j < a[i]; ++j) ++f[j];
update(i + 1, a[i] - 1, 1);
update(a[i], n, 1 - query(a[i]));
ans[i] = query(i, k);
// for (int j = n; j >= a[i]; --j) f[j] -= f[a[i]] - 1;
// for (int j = i; j <= n; ++j) ans[i] += (f[j] <= k);
}
for (int i = 1; i <= n; ++i) std::cout << ans[i] << ' ';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

P11885 [RMI 2024] 跑酷 题解
https://sobaliuziao.github.io/2025/03/17/post/f22b9fd.html
作者
Egg_laying_master
发布于
2025年3月17日
许可协议