【HNOI2010】弹飞绵羊 题解(分块)

前言:其实这个题是用LCT做的,但蒟蒻因为太弱了,只会分块QAQ。

-----------------------------

题目链接

题目大意:给定$n$个装置,每个装置有弹力系数$k_i$,即在这个位置上会被弹到$i+k_i$。现在有两个操作:1.修改某个弹力装置的弹力系数。2.问从$x$开始,弹几次后所处位置大于$n$。

预处理在每个点需要被弹飞的次数$sum[i]$和到达的下一个点$out[i]$。然后进行分块。修改的时候只需要在所在块内的$sum$和$out$即可。

每次询问和修改的时间复杂度都是$O(\sqrt n)$。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int out[maxn],sum[maxn],num[maxn];
int n,m,block,tot;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline int getpos(int x)
{
    return (x-1)/block+1;
}
inline void work(int l,int r)
{
    for (int i=r;i>=l;i--) 
    {
        if (i+num[i]>getpos(i)*block) sum[i]=1,out[i]=i+num[i];
        else sum[i]=sum[i+num[i]]+1,out[i]=out[i+num[i]];
    }
}
int main()
{
    n=read();block=sqrt(n);
    tot=n/block;if (n%block) tot++;
    for (int i=1;i<=n;i++) num[i]=read();
    work(1,n);
    m=read();
    for (int i=1;i<=m;i++)
    {
        int flag=read(),y=read()+1;
        if (flag==1)
        {
            int ans=sum[y],x=out[y];
            for (int j=getpos(y);j<=tot&&x<=n;j++) ans+=sum[x],x=out[x];
            printf("%d\n",ans);
        }
        else{
            int z=read();num[y]=z;
            work((getpos(y)-1)*block+1,getpos(y)*block);
        }
    }
    return 0;
}

 

posted @ 2020-07-13 14:24  我亦如此向往  阅读(156)  评论(0编辑  收藏  举报