1. 程式人生 > >bzoj 2002[Hnoi2010]Bounce 彈飛綿羊(分治分塊)

bzoj 2002[Hnoi2010]Bounce 彈飛綿羊(分治分塊)

hnoi names 直接 latex data key ons log scanf

Description

某天,Lostmonkey發明了一種超級彈力裝置,為了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,Lostmonkey在地上沿著一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。為了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均為正整數。

Input

第一行包含一個整數n,表示地上有n個裝置,裝置的編號從0到n-1,接下來一行有n個正整數,依次為那n個裝置的初始彈力系數。第三行有一個正整數m,接下來m行每行至少有兩個數i、j,若i=1,你要輸出從j出發被彈幾次後被彈飛,若i=2則還會再輸入一個正整數k,表示第j個彈力裝置的系數被修改成k。對於20%的數據n,m<=10000,對於100%的數據n<=200000,m<=100000

Output

對於每個i=1的情況,你都要輸出一個需要的步數,占一行。

Sample Input

4
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3
這個題給了10s,但是也不能亂搞. 我們現將彈簧進行分塊,對於每個彈簧我們記錄它跳出自己所在塊的步數times跟跳出當前塊的落點pos 這樣我們對於每次更改就可以只更改x所在塊中位於x之前的點,跟x自己,這樣是每個詢問是技術分享 然而對於每一個詢問由於我們記錄的pos是跳出當前塊的落點,這樣最多我們跳技術分享塊,所以也是技術分享 綜合復雜度技術分享 寫完這個題感覺分塊真是優美
 1 #include <bits/stdc++.h>
 2
3 using namespace std; 4 const int maxn = 220000; 5 int n,m; 6 int q,op; 7 int a[maxn]; 8 int pos[maxn],times[maxn]; 9 int main() 10 { 11 //freopen("de.txt","r",stdin); 12 while (~scanf("%d",&n)){ 13 memset(pos,-1,sizeof pos); 14 for (int i=0;i<n;++i){ 15 scanf("
%d",&a[i]); 16 } 17 int sz = (int) sqrt(n); 18 for (int i=n-1;i>=0;--i){//從後向前初始化pos,times 19 int tmp = a[i]+i; 20 if (tmp>n) 21 pos[i]=-1,times[i]=1;//直接跳出邊界 22 else if (tmp>=(i/sz+1)*sz) 23 pos[i] = tmp,times[i]=1;//跳出了當前塊 24 else 25 pos[i] = pos[tmp],times[i]=times[tmp]+1;//跳到了塊內的另一個點 26 } 27 scanf("%d",&m); 28 for (int i=0;i<m;++i){ 29 scanf("%d",&q); 30 if (q==1){ 31 int x; 32 int ans = 0; 33 scanf("%d",&x); 34 for (int j=x;j!=-1;j=pos[j]){ 35 ans+=times[j]; 36 } 37 printf("%d\n",ans); 38 } 39 else{ 40 int x,y; 41 scanf("%d%d",&x,&y); 42 a[x]=y; 43 for (int j=x;j>=x/sz*sz;j--){//更新只更新x所在塊裏面位於x之前的塊跟x自己 44 int tmp=j+a[j]; 45 if (tmp>=n) 46 pos[j]=-1,times[j]=1; 47 else if (tmp>=(j/sz+1)*sz) 48 pos[j]=tmp,times[j]=1; 49 else 50 pos[j]=pos[tmp],times[j] = times[tmp]+1; 51 } 52 } 53 } 54 } 55 return 0; 56 }

bzoj 2002[Hnoi2010]Bounce 彈飛綿羊(分治分塊)