bzoj2002

bzoj2002

题意

给定 n 个值 a,表示某人跳到这个点 ( i ) 后会向后跳到 ( i + a ) 这个点,直到跳出范围 n 。
两个操作:

  1. 询问,从查询的点开始需要多少次跳出范围 n ;
  2. 更新单个节点的值 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;
}
posted @ 2017-05-25 00:50  ftae  阅读(99)  评论(0编辑  收藏