1. 程式人生 > >[HNOI2010]彈飛綿羊(分塊)

[HNOI2010]彈飛綿羊(分塊)

存在 name reg ring include size div string etc

題目描述

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

輸入輸出格式

輸入格式:

第一行包含一個整數n,表示地上有n個裝置,裝置的編號從0到n-1。

接下來一行有n個正整數,依次為那n個裝置的初始彈力系數。

第三行有一個正整數m,

接下來m行每行至少有兩個數i、j,若i=1,你要輸出從j出發被彈幾次後被彈飛,若i=2則還會再輸入一個正整數k,表示第j個彈力裝置的系數被修改成k。

輸出格式:

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

輸入輸出樣例

輸入樣例#1: 復制
4
1 2 1 1
3
1 1
2 1 1
1 1
輸出樣例#1: 復制
2
3

說明

對於20%的數據n,m<=10000,對於100%的數據n<=200000,m<=100000

題解

  這裏需要我們處理出每一塊中,進入某個點後,會進入下一個塊的哪一個點,需要幾次才能彈出塊,修改時記得同時修改相應塊的內容。

  靠大佬自己思維了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=500001;
int n,m,ch[N],tmp,belong[N],l[N],r[N],num,out[N],sum[N];
int read()
{
    int x=0,w=1;char ch=getchar();
    
while(ch>9||ch<0){if(ch==-)w=-1;ch=getchar();} while(ch>=0&&ch<=9)x=x*10+ch-0,ch=getchar(); return w*x; } void build() { num=tmp;if(tmp*tmp<n)num++; for(int i=1;i<=num;i++) { l[i]=num*(i-1)+1;r[i]=num*i; } r[num]=n; int s=1 ; for (int i=1;i<=n;i++) {if (i>r[s]) s++; belong[i]=s;} } void change(int left,int right) { for(int i=right;i>=left;i--) { if(i+ch[i]>r[belong[i]])sum[i]=1,out[i]=i+ch[i]; else sum[i]=sum[i+ch[i]]+1,out[i]=out[i+ch[i]]; } } int main() { n=read();tmp=sqrt(n); for(int i=1;i<=n;i++) { ch[i]=read(); } build(); change(1,n); m=read(); for(int i=1;i<=m;i++) { int qwq; qwq=read(); if(qwq==1) { int x;x=read();x++; int ans=sum[x],qwq=out[x]; for(int i=belong[x];i<=tmp&&qwq<=n;i++) ans+=sum[qwq],qwq=out[qwq]; printf("%d\n",ans); } else { int x,y;x=read();x++;y=read();ch[x]=y; change(l[belong[x]],r[belong[x]]); } } return 0; }

[HNOI2010]彈飛綿羊(分塊)