链接
思路:
LCT
L
C
T
可以解决, 但是分块的编码速度更快,先预处理出每个位置跳出当前块需要多少步,然后对于每个查询,直接遍历跳出每一块的步数,对于每个修改,暴力更新那个位置所属的块的所有位置信息,时间复杂度都是
O(nn−−√)
O
(
n
n
)
。
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 2e5 + 10;
using namespace std;
int n, m, T, kase = 1;
int a[maxn], b[maxn], dp[maxn];
int bel[maxn], nxt[maxn];
void init() {
int sz = sqrt(n + 0.5) + 1;
int from = 1, tot = 0;
for(int i = 1; i <= n; i++) {
bel[i] = from; tot++;
if(tot == sz || i == n) {
from++;
for(int j = i; j >= i - tot + 1 && bel[j] == bel[i]; j--) {
if(bel[j] == bel[a[j]]) {
dp[j] = dp[a[j]] + 1;
nxt[j] = nxt[a[j]];
} else {
dp[j] = 1;
nxt[j] = a[j];
}
}
tot = 0;
}
}
}
int query(int x) {
int ans = 0;
while(x <= n) {
ans += dp[x];
x = nxt[x];
}
return ans;
}
void update(int x, int data) {
a[x] = data + x;
for(int i = x; i >= 1 && bel[i] == bel[x]; i--) {
if(bel[i] == bel[a[i]]) {
dp[i] = dp[a[i]] + 1;
nxt[i] = nxt[a[i]];
} else {
dp[i] = 1;
nxt[i] = a[i];
}
}
}
int main() {
while(scanf("%d", &n) != EOF) {
memset(bel, -1, sizeof bel);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] = i + a[i];
}
init();
scanf("%d", &m);
while(m--) {
int op, x, y;
scanf("%d", &op);
if(op == 1) {
scanf("%d", &x);
int ans = query(x + 1);
printf("%d\n", ans);
} else {
scanf("%d %d", &x, &y);
update(x + 1, y);
}
}
}
return 0;
}