Эффективная обработка прыжков по массиву с обновлениями
n, m = map(int, input().split())
A = list(map(int, input().split()))
dp = [[-1] * 2 for _ in range(n)]
c = int(n ** 0.5) + 1
for i in range(n - 1, -1, -1):
if i + A[i] >= n:
dp[i][0] = 1
dp[i][1] = -1
else:
if (i + A[i]) // c > i // c:
dp[i][0] = 1
dp[i][1] = i + A[i]
else:
dp[i][0] = dp[i + A[i]][0] + 1
if dp[i + A[i]][1] == -1:
dp[i][1] = i + A[i]
dp[i][0] = 1
else:
dp[i][1] = dp[i + A[i]][1]
for _ in range(m):
s = list(map(int, input().split()))
if s[0] == 0:
j = s[1] - 1
A[j] = s[2]
for i in range(min((j // c + 1) * c - 1, n - 1), j // c * c - 1, -1):
if i + A[i] >= n:
dp[i][0] = 1
dp[i][1] = -1
else:
if (i + A[i]) // c > i // c:
dp[i][0] = 1
dp[i][1] = i + A[i]
else:
dp[i][0] = dp[i + A[i]][0] + 1
if dp[i + A[i]][1] == -1:
dp[i][1] = i + A[i]
dp[i][0] = 1
else:
dp[i][1] = dp[i + A[i]][1]
else:
i = s[1] - 1
z = 0
while dp[i][1] != -1:
z += dp[i][0]
i = dp[i][1]
print(i + 1, z + 1)
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n, m;
cin >> n >> m;
vector<int> A(n);
for (int i = 0; i < n; i++) {
cin >> A[i];
}
int c = sqrt(n) + 1;
vector<vector<int>> dp(n, vector<int>(2, -1));
for (int i = n - 1; i >= 0; i--) {
if (i + A[i] >= n) {
dp[i][0] = 1;
dp[i][1] = -1;
} else {
if ((i + A[i]) / c > i / c) {
dp[i][0] = 1;
dp[i][1] = i + A[i];
} else {
dp[i][0] = dp[i + A[i]][0] + 1;
if (dp[i + A[i]][1] == -1) {
dp[i][1] = i + A[i];
dp[i][0] = 1;
} else {
dp[i][1] = dp[i + A[i]][1];
}
}
}
}
for (int q = 0; q < m; q++) {
int type;
cin >> type;
if (type == 0) {
int j, x;
cin >> j >> x;
j--;
A[j] = x;
int block_start = (j / c) * c;
int block_end = min((j / c + 1) * c - 1, n - 1);
for (int i = block_end; i >= block_start; i--) {
if (i + A[i] >= n) {
dp[i][0] = 1;
dp[i][1] = -1;
} else {
if ((i + A[i]) / c > i / c) {
dp[i][0] = 1;
dp[i][1] = i + A[i];
} else {
dp[i][0] = dp[i + A[i]][0] + 1;
if (dp[i + A[i]][1] == -1) {
dp[i][1] = i + A[i];
dp[i][0] = 1;
} else {
dp[i][1] = dp[i + A[i]][1];
}
}
}
}
} else {
int i;
cin >> i;
i--;
int steps = 0;
while (dp[i][1] != -1) {
steps += dp[i][0];
i = dp[i][1];
}
cout << i + 1 << " " << steps + 1 << "\n";
}
}
return 0;
}
Задача: есть массив A. Из позиции i можно прыгнуть на A[i] позиций вперёд. Нужно отвечать на запросы: найти последнюю позицию и количество прыжков, а также обновлять A[i].
При изменении A[j] достаточно пересчитать только позиции в том же блоке, что и j (двигаясь справа налево).
Начинаем с позиции i и прыгаем по блокам, суммируя количество шагов, пока не достигнем последней позиции.
Сложность: O((n + m) × √n) — предподсчёт O(n), запрос O(√n), обновление O(√n).
Ввод:
n m — количество элементов и количество запросовa1 a2 ... an — массив A (длины прыжков)0 j x — присвоить A[j] = x1 i — из позиции i (1-индексация) выполнять прыжки, пока не выйдем за пределы, вывести последнюю позицию и количество прыжков5 4
2 1 3 2 1
1 1
0 3 1
1 1
1 4
Вывод:
5 3
4 2
4 1
Введите массив и запросы: