bzoj2002
bzoj2002
题意
给定 n 个值 a,表示某人跳到这个点 ( i ) 后会向后跳到 ( i + a ) 这个点,直到跳出范围 n 。
两个操作:
- 询问,从查询的点开始需要多少次跳出范围 n ;
- 更新单个节点的值 a;
分析
分块,这里分块的作用是平衡查询和更新的复杂度(O(sqrt(n)) ),这样总的复杂度(O(n * sqrt(n)))。
分成 sqrt(n) 个块,预处理块内每个点离开单个块的所需次数。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
const int SIZE = 400;
int a[MAXN], nxt[MAXN], cnt[MAXN];
int n;
void update(int high, int low)
{
for(int j = high; j >= low; j--)
{
if(j + a[j] > high)
{
nxt[j] = j + a[j];
cnt[j] = 1;
}
else
{
nxt[j] = nxt[j + a[j]];
cnt[j] = cnt[j + a[j]] + 1;
}
}
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i += SIZE)
{
int high = min(n, i + SIZE - 1);
update(high, i);
}
int m;
scanf("%d", &m);
while(m--)
{
int k, x;
scanf("%d%d", &k, &x);
x++;
if(k == 1)
{
int s = 0;
while(x <= n)
{
s += cnt[x];
x = nxt[x];
}
printf("%d\n", s);
}
else
{
int d;
scanf("%d", &d);
a[x] = d;
int low = (x - 1) / SIZE * SIZE + 1;
int high = min(n, low + SIZE - 1);
update(high, low);
}
}
return 0;
}