P3203 [HNOI2010]弹飞绵羊

题目
暴力时间复杂度是(O(n^2))
涉及到区间的题,可以用分块去操作
那么记录每个点出所在的分块所需要次数和出分块后的位置即可
然后暴力

对于非典型分块,需要处理好每个分块的左右区间,以及0和n + 1所在分块情况

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 2e5 + 5;
int n, m, unt;
int bl[N], a[N], to[N], f[N], l[N];
void Change(int pos, int k){
    a[pos] = k;
    for(int i = l[bl[pos] + 1] - 1; i >= l[bl[pos]]; i--){
        if(i + a[i] >= l[bl[i] + 1]){
            f[i] = 1;
            to[i] = i + a[i];
        }else{
            f[i] = f[i + a[i]] + 1;
            to[i] = to[i + a[i]];
        }
    }
}
int Query(int pos){
    int ans = 0;
    while(pos <= n){
        ans += f[pos];
        pos = to[pos];
    }
    return ans;
}
int main(){
    scanf("%d", &n);
    unt = sqrt(n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        bl[i] = (i - 1) / unt + 1;
        if (bl[i] != bl[i - 1]) l[bl[i]] = i;
    }
    l[bl[n] + 1] = n + 1;
    for(int i = n; i >= 1; i--){
        if(i + a[i] >= l[bl[i] + 1]){
            f[i] = 1;
            to[i] = i + a[i];
        }else{
            f[i] = f[i + a[i]] + 1;
            to[i] = to[i + a[i]];
        }
    }
    scanf("%d", &m);
    while(m--){
        int op, x, k;
        scanf("%d", &op);
        if(op == 1){
            scanf("%d", &x);
            printf("%d
", Query(x + 1));
        }else{
            scanf("%d%d", &x, &k);
            Change(x + 1, k);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Emcikem/p/12921390.html