整理的算法模板合集: ACM模板
已知:暴力 + 暴力 + 1 0 5 10^5 105 = 分块
设 need[i]
表示从 i
开始,跳出所在块的步数;ver[i]
表示跳出当前所在的块后到了哪里;
//#pragma GCC optimize("Ofast")
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bitset>
#include<map>
#define debug(x) cout << x << "ok" << endl
typedef long long ll;
#define file freopen("1.in", "r", stdin);freopen("1.out", "w", stdout);
const int N = 2e5 + 7, M = 1e5 + 7, INF = 0x3f3f3f3f;
const int B = 260, B2 = 300;
using namespace std;
ll read()
{
ll x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}
ll n, m;
ll val[N];
ll block;
ll need[N], ver[N];
ll bi[N];
ll st[N];//每个块开始的编号
ll ed[N];//每个块结束的编号
inline void modify(int p, int w)
{
val[p] = w;
for(register int i = st[bi[p] + 1] - 1; i >= st[bi[p]]; -- i){
if(i + val[i] >= st[bi[p] + 1]){
need[i] = 1;
ver[i] = i + val[i];
}
else {
need[i] = need[i + val[i]] + 1;
ver[i] = ver[i + val[i]];
}
}
}
inline ll query(int p)
{
int res = 0;
while(p <= n){//主要是这点,可以直接出去
res += need[p];
p = ver[p];
}
return res;
}
int main()
{
n = read();
block = sqrt(n);
for(int i = 1; i <= n; ++ i){
val[i] = read();
bi[i] = (i - 1) / block + 1;
//if(bi[i] != bi[i - 1])//说明一个新的块开始了
// st[bi[i]] = i;
}
//st[bi[n] + 1] = n + 1;//一个虚拟节点表示已经被弹飞了
for(int i = 1; i <= block; ++ i){
st[i] = (i - 1) * block + 1;
ed[i] = i * block;
}
if(ed[block] < n){
block ++ ;//一个角块
st[block] = ed[block - 1] + 1;
ed[block] = n;
}
for(int i = n; i >= 1; -- i){
if(i + val[i] >= st[bi[i] + 1]){
need[i] = 1;//可以一步出去
ver[i] = i + val[i];
}
else {
need[i] = need[i + val[i]] + 1;//所以我们是倒着推的
ver[i] = ver[i + val[i]];//递推
}
}
m = read();
while(m -- ){
int op = read(), x = read(), y;
x ++ ;//题目里的编号是0 ~ n - 1,所以需要 ++
if(op == 1){
printf("%lld\n", query(x));
}
else {
y = read();
modify(x, y);
}
}
return 0;
}