HYSBZ-2002 Bounce 弹飞绵羊(分块)

题意

n 个装置排成一排,第 i 个装置都有一个弹力系数 k i ( k i > 0 ) ,能让绵羊向后弹 k i 格,当绵羊弹出这 n 个装置,即为弹飞。在线完成 m 次操作,操作分两种:修改某个弹簧的弹力系数,把绵羊放在一号弹簧并询问弹多少次将弹飞。
1 n , m 10000

思路

这类题目总还是要从暴力出发并用数据结构优化。我们发现,直接暴力时查询的操作是 O ( n ) 的,于是通过分块优化查询。我们通过把 n 个点分成 n 块,并维护以这个点为起点并跳出这个块的次数和位置。这样更新一个点的弹力系数可以只更新这个点以及这个块内之前的点。查询只用 O ( n ) 的跳块即可。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 200003
typedef long long LL;
using namespace std;

struct Block
{
    int a[N],loc[N],jmp[N];
    int bs,n;
    void refresh(int x)
    {
        int nxt=min(n+1,x+a[x]);
        if(nxt==n+1||nxt/bs!=x/bs)
        {
            loc[x]=nxt;
            jmp[x]=1;
        }
        else loc[x]=loc[nxt],jmp[x]=jmp[nxt]+1;
    }
    void Build(int _)
    {
        bs=sqrt(n=_);
        FOR(i,1,n)scanf("%d",&a[i]);
        jmp[n+1]=0;loc[n+1]=n+1;
        DOR(i,n,1)refresh(i);
        return;
    }
    void update(int x,int val)
    {
        int kx=x/bs;
        a[x]=val;
        DOR(i,x,kx*bs)refresh(i);
        return;
    }
    int query(int x)
    {
        int shot=x,cnt=0;
        while(shot!=n+1)
        {
            cnt+=jmp[shot];
            shot=loc[shot];
        }
        return cnt;
    }
}B;

int main()
{
    int n,m;
    scanf("%d",&n);
    B.Build(n);
    scanf("%d",&m);
    FOR(i,1,m)
    {
        int x,y,z;
        scanf("%d",&x);
        if(x==1)
        {
            scanf("%d",&y);
            printf("%d\n",B.query(y+1));
        }
        else if(x==2)
        {
            scanf("%d%d",&y,&z);
            B.update(y+1,z);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/81268288