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\n", Query(x + 1));
        }else{
            scanf("%d%d", &x, &k);
            Change(x + 1, k);
        }
    }
    return 0;
}
posted @ 2020-05-20 08:40  Emcikem  阅读(126)  评论(0编辑  收藏  举报