【bzoj2002】弹飞绵羊——分块

这道题是很简单的分块吧,统计每个块里要中转的次数(即st数组),最后输出即可。

如果修改某个弹力装置的弹力系数,那么要从这个装置开始往回走到这一块的最左端(即l[belong[b]]),修改相对应的st数组和pt数组,它前面的块和后面的块都不受影响(因为st统计的是走到这一步到走出这一个装置所属的块所需的步数)。

具体实现细节看代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
const int maxn=200010;
using namespace std;
int n,m,block,cnt;
int pt[maxn],st[maxn],k[maxn],belong[maxn];
int l[1005],r[1005];
void print(int w)
{
    int t=0;
    do{
        t+=st[w];
        w=pt[w];
    }while(w);
    printf("%d
",t);
}
int main()
{
    scanf("%d",&n);
    block=sqrt(n);
    for(int i=1;i<=n;i++)
        scanf("%d",&k[i]);
    if(n%block)cnt=n/block+1;
    else cnt=n/block;//cnt存的是块的块数
    for(int i=1;i<=cnt;i++)
    {
        l[i]=(i-1)*block+1;
        r[i]=i*block;
    } 
    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;
    for(int i=n;i>=1;i--)
    {
        if(i+k[i]>n)st[i]=1;
        else if(belong[i]==belong[i+k[i]])
            st[i]=st[i+k[i]]+1,pt[i]=pt[i+k[i]];
        else st[i]=1,pt[i]=i+k[i];
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d %d",&a,&b);
        b++;
        if(a==1)print(b);
        else{
            scanf("%d",&c);
            k[b]=c;
            for(int j=b;j>=l[belong[b]];j--)
            {
                if(belong[j]==belong[j+k[j]])
                    st[j]=st[j+k[j]]+1,pt[j]=pt[j+k[j]];
                else st[j]=1,pt[j]=j+k[j];
            }
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/JKAI/p/6964446.html