bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊 分块

题目链接

Description

某天,(Lostmonkey)发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,(Lostmonkey)在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数(k_i),当绵羊达到第i个装置时,它会往后弹(k_i)步,达到第(i+k_i)个装置,若不存在第(i+k_i)个装置,则绵羊被弹飞。绵羊想知道当它从第(i)个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,(Lostmonkey)可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

思路

分块,维护:

  1. 每个点跳几次跳到下一个块
  2. 跳到下一个块的什么位置

初始化:(O(n))
修改:(O(sqrt n))
查询:(O(sqrt n))

Code

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 200010
using namespace std;
typedef long long LL;
int a[maxn], n, blo, bl[maxn], num;
struct node { int cnt, p; }v[maxn];
void init() {
    F(i, 0, num) {
        int ed = min((i+1)*blo-1, n-1),
            st = i*blo;
        dF2(j, ed, st) {
            int ne = j+a[j];
            if (ne>ed) v[j] = {1, ne};
            else v[j] = v[ne], ++v[j].cnt;
        }
    }
}
void modify(int x, int c) {
    a[x] = c;
    int st = bl[x]*blo, ed = min((bl[x]+1)*blo-1, n-1);
    dF2(i, x, st) {
        int ne = i+a[i];
        if (ne > ed) v[i] = {1, ne};
        else v[i] = v[ne], ++v[i].cnt;
    }
}
int query(int x) {
    int ret=0;
    while (x < n) {
        ret += v[x].cnt;
        x = v[x].p;
    }
    return ret;
}
int main() {
    scanf("%d", &n); blo = sqrt(n);
    F(i, 0, n) {
        scanf("%d", &a[i]);
        bl[i] = i/blo;
    }
    num = bl[n-1]+1;
    init();
    int m;
    scanf("%d", &m);
    F(i, 0, m) {
        int op, x, y;
        scanf("%d", &op);
        if (op==1) {
            scanf("%d",&x);
            printf("%d
", query(x));
        }
        else {
            scanf("%d%d", &x,&y);
            modify(x,y);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/8479764.html