BZOJ 2002 Hnoi2010 彈飛綿羊 分塊

題意

某天,Lostmonkey發明了一種超級彈力裝置,爲了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。

遊戲一開始,Lostmonkey在地上沿着一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。

綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。

爲了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均爲正整數。

n200000

分析

正解LCT。
但是可以考慮分塊。

我們將位置分成n 塊,對於每一塊進行維護。
每一塊我們需要保存以下幾個值:
wij :第i 塊第j 個位置能往前跳多少個位置;
lastij :第i 塊第j 個位置在本塊跳到的最後位置;
cntij :第i 塊第j 個位置跳到本塊最後一個位置需要多少步;

這樣可以解決詢問操作:
假設從x 開始跳,首先xlast 跳到塊尾,答案累加用cnt ,再用w 數組將x 跳到塊尾位置跳到的下一個位置,直到跳出。

現在只用解決維護就可以了。

最初的時候,我們需要求這三個的初始值。
由於每一塊的取值不受外界影響,所以我們每一塊分開來求,使用函數Calculate(i) 表示求第i 塊。
從塊內的最後一個元素往前遞推,分跳到塊內、跳到塊外處理。

後來的更改,只用暴力找到位置更改了,然後整塊用Calculate 重新求一次。

代碼

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;

const int N=200010;
const int BLOCK_SIZE=500;
const int BLOCK_MAX=500;

int n;

int unit,tot;
int w[BLOCK_SIZE][BLOCK_MAX];
int cnt[BLOCK_SIZE][BLOCK_MAX];
int last[BLOCK_SIZE][BLOCK_MAX];

inline int Read(void)
{
    int x=0,f=1; char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

void Calculate(int nb)
{
    int bnum=min(unit,n-(nb-1)*unit); int gb,gl;
    for (int i=bnum;i>=1;i--)
        if (i+w[nb][i]>bnum)
        {
            cnt[nb][i]=1;
            last[nb][i]=i;
        }
        else
        {
            cnt[nb][i]=cnt[nb][i+w[nb][i]]+1;
            last[nb][i]=last[nb][i+w[nb][i]];
        }
}

void Init(void)
{
    n=Read();   
    unit=(int)sqrt(n);

    int cur=unit;
    for (int i=1;i<=n;i++)
    {
        if (cur==unit) tot++,cur=0;
        w[tot][++cur]=min(Read(),n+1);
    }

    for (int i=1;i<=tot;i++) Calculate(i);
}

int m;

int Query(int x)
{
    int nb,nl,sum=0;
    for (;x<=n;)
    {
        nb=(x-1)/unit+1,nl=x-(nb-1)*unit;
        sum+=cnt[nb][nl];
        x=(nb-1)*unit+last[nb][nl]+w[nb][last[nb][nl]];
    }
    return sum;
}

void Update(int x,int y)
{
    int nb=(x-1)/unit+1,nl=x-(nb-1)*unit;
    w[nb][nl]=y;
    Calculate(nb);
}

void Work(void)
{
    int k,x,y; m=Read();
    for (int i=1;i<=m;i++)
    {
        k=Read();
        if (k==1)
        {
            x=Read()+1;
            printf("%d\n",Query(x));
        }
        else
        {
            x=Read()+1,y=Read();
            Update(x,y);
        }
    }
}

int main(void)
{
    Init();
    Work();
    return 0;
}
發佈了65 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章