bzoj2002

题意:

一条直线上有n个装置,每个装置设定初始弹力系数,当达到第i个装置时,它会往后弹步,达到第个装置,若不存在第个装置,则绵羊被弹飞。

有两种操作:

1 x:当它从第i个装置起步时,被弹几次后会被弹飞。

2 x y:修改第x个弹力装置的弹力系数为y。

思路:

因为直接暴力的话一步一步弹太慢了,是的,可以考虑分块提前把弹几步处理出来,这样就可以把弹的复杂度变成

所以要处理出来每一个装置到下一块的落点和步数。

分为三种情况:

1.下一步直接弹出:pos=-1,step=1;

2.下一步弹到块内:pos=pos[Next[i]],step=step[Next[i]]+1;

3.下一步弹到后面的块内:pos=Next[i],step=1。

对于查询,循环求出步数。

对于修改,因为一个装置的修改会影响到块内装置的信息,所以从后往前更新块内装置的信息即可。

复杂度为

代码:

int n;
int num;//分块的个数
int belong[200010];//每个数属于哪个分块
int block;//每个块的大小
int lef[200010],rig[200010];//该块的左/右端点位置
int pos[200010],step[200010];//到下一块的落地位置/最小步数
int Next[200010];
void build()
{
    block=sqrt(n);
    num=n/block;if(n%block)num++;
    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;
    for(int i=1;i<=num;i++)
    {
        lef[i]=(i-1)*block+1;
        rig[i]=i*block;
    }
    rig[num]=n;//最后一块不满的情况
}
int main()
{
    scanf("%d",&n);
    build();
    for(int i=1;i<=n;i++)
        scanf("%d",&Next[i]);
    for(int i=n;i>=1;i--)
    {
        if(i+Next[i]>n)//直接弹出
        {
            pos[i]=-1;
            step[i]=1;
        }
        else if(i+Next[i]<=rig[belong[i]])//在同一块内
        {
            pos[i]=pos[i+Next[i]];
            step[i]=step[i+Next[i]]+1;
        }
        else//弹出当前块
        {
            pos[i]=i+Next[i];
            step[i]=1;
        }
    }
    int m,op;
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&op);
        if(op==1)   //查询
        {
            int ans=0,cur;
            scanf("%d",&cur);
            cur++;
            while(cur!=-1)
            {
                ans+=step[cur];
                cur=pos[cur];
            }
            printf("%d\n",ans);
        }
        else
        {
            int x,y;
            scanf("%d%d",&x,&y);//把x装置变为系数变为y
            x++;
            Next[x]=y;
            for(int i=x;i>=lef[belong[x]];i--)
            {
                if(i+Next[i]>n)//直接弹出
                {
                    pos[i]=-1;
                    step[i]=1;
                }
                else if(i+Next[i]<=rig[belong[i]])//在同一块内
                {
                    pos[i]=pos[i+Next[i]];
                    step[i]=step[i+Next[i]]+1;
                }
                else//弹出当前块
                {
                    pos[i]=i+Next[i];
                    step[i]=1;
                }
            }
        }
    }
    return 0;
}
HDU6394

update…


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

南京网络赛E 状压dp(反省...) Previous
__builtin_系列函数 Next