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;
}
I‘m Stein, welcome to my blog