彈飛綿羊 分塊法

A - Bounce 彈飛綿羊

 HYSBZ - 2002 

某天,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

線段樹也學了挺久了,但是一直沒去學分塊。最近學了一下分塊,還是很好理解的。

分塊就是一個優美的暴力法,優美是因爲它將n範圍分爲了 sqrt(n)個區間,每個區間大小爲sqrt(n)

對sqrt(n)進行暴力。

 我們將n先分塊,和分塊的基本操作做完。 用e【i】表示用當前i點進入下一個塊需要跳多少下。 en【i】表示當前i點跳入下個區間的落點。

 

#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <bitset>
#define  LL long long
#define  ULL unsigned long long
#define mod 10007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
using namespace std;
const int maxn = 1e6 + 5;
int block,l[maxn],r[maxn],num,a[maxn],n,belong[maxn];
int e[maxn],en[maxn];
void build(){
  block = sqrt(n);
  num = n/block;if(n % block) num++;
  for(int i = 1; i <= num; i++) l[i] = (i - 1)*block + 1,r[i] = i * block;
  r[num] = n;
  for(int i = 1; i <= n; i++){
    belong[i] = (i - 1)/block + 1;
  }
  //int j = num;
  for(int i = n; i > 0; i--){
    if(a[i] + i > r[belong[i]]){//若當前點能夠跳入下個塊
      e[i] = 1;//只需跳一次
      en[i] = a[i] + i;//進入下個區間的落點
    }
    else{
      e[i] = e[i + a[i]] + 1;//跳到本區間的點,跳的次數是 落點的進入下個區間的次數再+1
      en[i] = en[i + a[i]];//i進入下個區間的落點肯定是和當前區間內這個點進入下個區間的落點相同的。
    }
  }


}
void upDate(int s,int k)
{
    a[s] = k;//我們只用對當前區間進行暴力維護就行了,我們所有的操作都是隻針對當前區間的
    //int j = num;
  for(int i = s; i > r[belong[s] - 1]; i--){
    if(a[i] + i > r[belong[i]]){
      e[i] = 1;
      en[i] = a[i] + i;
    }
    else{
      e[i] = e[i + a[i]] + 1;
      en[i] = en[i + a[i]];
    }
  }


}
int query(int k)
{
    int ans = 0;
    for(int i = k; i <= n; i = en[i]){
      ans += e[i];
    }
    return ans;
}
int main()
{

    scanf("%d",&n);
    for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
    build();
    int m;
    scanf("%d",&m);
    while(m--){
      int opt;
      scanf("%d",&opt);
      if(opt == 1){
        int x;
        scanf("%d",&x);
        printf("%d\n",query(x + 1));
      }
      else if(opt == 2){
        int x,y;
        scanf("%d%d",&x,&y);
        upDate(x + 1,y);
      }
    }


    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章