[ H n o i 2010 ] [Hnoi2010] [Hnoi2010]弹飞绵羊
题解-
i
207
M
i207M
i207M
L
c
t
Lct
Lct裸题,分块也可做。
普通暴力在改变弹力系数时不大方便。
考虑分块,记录跳出块内所需步数
S
t
i
St_i
Sti和跳出块后到达的点
T
o
i
To_i
Toi,这样就只用考虑块内影响。
(真 全咕最大常数代码)
#include<cstdio>
#include<cmath>
const int MAXN = 2e5 + 10;
int N, M, Siz, Sum, Bel[MAXN], St[MAXN], To[MAXN], k[MAXN];
int min(int a, int b){return a < b ? a : b;}
void Update(int now)
{
for (int j = now * Siz; j >= (now - 1) * Siz + 1; j--)
{
if (j > N) continue;
if (j + k[j] > min(now * Siz, N)) To[j] = j + k[j], St[j] = 1;
else St[j] = St[j + k[j]] + 1, To[j] = To[j + k[j]];
}
}
int Query(int now)
{
int w = now, Ret = 0;
while (w <= N) Ret += St[w], w = To[w];
return Ret;
}
void init()
{
Siz = sqrt(N), Sum = N / Siz; if (N % Siz) Sum++;
for (int i = 1; i <= N; i++) Bel[i] = (i - 1) / Siz + 1;
for (int i = Sum; i >= 1; i--) Update(i);
}
int main()
{
scanf("%d", &N);
for (int i = 1; i <= N; i++) scanf("%d", &k[i]);
init();
scanf("%d", &M);
for (int i = 1; i <= M; i++)
{
int opt, x, y; scanf("%d%d", &opt, &x);
if (opt == 1) printf("%d\n", Query(x + 1));
if (opt == 2) scanf("%d", &y), k[x + 1] = y, Update(Bel[x + 1]);
}
return 0;
}