这几天一直在bzoj水不能见人的水题…有时间补补题解吧【说得好像这题不水一样
很简单的分块!
第一次写到这么简单的分块!
整个人都舒爽了!
虽然还是WA了两次…妈的我只是写完一激动忘了输出后加回车…
将整个长区间分成近似于sqrt(n)块【分块方法随意,满足可逆性即可
对于每一块,处理出块内每个点弹出这一块所需步数
然后每次查询最多累计sqrt(n)次(块数次)
每次修改最多修改sqrt(n)次(块大小次)
完美【呸
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 200005;
int n,m,len,c,x,y,k[maxn],block[maxn],next[maxn],step[maxn];
void f(int p,int i)
{
if(p>=n)step[i] = 1, next[i]=-1;
else if(block[p]!=block[i]) step[i]=1,next[i]=p;
else step[i] = step[p]+1, next[i]=next[p];
}
void cal(void)
{
for(int i = n-1; i >= 0; i--)
f(i+k[i],i);
}
int query(int x,int ret)
{
ret+=step[x];
if(next[x]==-1)return ret;
return query(next[x],ret);
}
void change(int x,int y)
{
if(k[x]==y)return;
k[x]=y;
int temp =(block[x]-1)*len;
for(int i = x; i >= temp; i--)
f(i+k[i],i);
}
int main (void)
{
scanf("%d",&n);
len = sqrt(n);
for(int i = 0; i < n; i++)
{
scanf("%d",&k[i]);
block[i]=i/len+1;
}
cal();
scanf("%d",&m);
for(int i = 0; i < m; i++)
{
scanf("%d%d",&c,&x);
if(c==1)printf("%d\n",query(x,0));
else
{
scanf("%d",&y);
change(x,y);
}
}
return 0;
}