2002: [Hnoi2010]Bounce 彈飛綿羊
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
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
3
——分割線——
彈飛綿羊QAQ這道題目名字很親和,其實好坑爹!一開始評測還以爲要T、結果A了。好開心!
好吧,言歸正傳,這道題目用分塊的做法可以過。看Hzwer的博客貌似用動態樹纔是更好的做法Orz……
分塊的做法就是將n個機器分成根號n塊,處理個機器走幾步可以走出本塊,並且到達哪一塊的那一個機器。然後球答案的時候最多隻要算根號n次,而每次更新機器也最多隻要根號n次,這樣把兩個的複雜度平衡了。就可以過了。
代碼:【中途有一個變量寫錯了,特意寫了個Arrest查了好久、QAQ】
#include<cstdio>
#include<cmath>
using namespace std;
int n;
struct Node{
int num;
int index[450];
int k[450];
int step[450];
int to[450];
int next[450];
};
Node node[450];
int m;
int sn;
int cnt=0;
inline void calc(){
for (int i=1;i<=cnt;i++){
for (int j=node[i].num;j>=1;j--){
if (node[i].index[j]+node[i].k[j]>n){
node[i].step[j]=1;
node[i].next[j]=-1;
}else{
if (node[i].k[j]+j<=node[i].num){
node[i].to[j]=node[i].to[j+node[i].k[j]];
node[i].step[j]=node[i].step[j+node[i].k[j]]+1;
node[i].next[j]=node[i].next[j+node[i].k[j]];
}else{
int tempcnt=i+1;
int tempk=node[i].k[j]-(node[i].num-j);
while(tempk>node[tempcnt].num){
tempk-=node[tempcnt].num;
tempcnt++;
}
node[i].to[j]=tempcnt;
node[i].next[j]=tempk;
node[i].step[j]=1;
}
}
}
}
}
inline void calc(int index,int val){
node[(index-1)/sn+1].k[(index-1)%sn+1]=val;
int i=(index-1)/sn+1;
for (int j=(index-1)%sn+1;j>=1;j--){
if (node[i].index[j]+node[i].k[j]>n){
node[i].step[j]=1;
node[i].next[j]=-1;
}else{
if (node[i].k[j]+j<=node[i].num){
node[i].to[j]=node[i].to[j+node[i].k[j]];
node[i].step[j]=node[i].step[j+node[i].k[j]]+1;
node[i].next[j]=node[i].next[j+node[i].k[j]];
}else{
int tempcnt=i+1;
int tempk=node[i].k[j]-(node[i].num-j);
while(tempk>node[tempcnt].num){
tempk-=node[tempcnt].num;
tempcnt++;
}
node[i].to[j]=tempcnt;
node[i].next[j]=tempk;
node[i].step[j]=1;
}
}
}
}
inline void Arrest(){
printf("Call Cnts:\n");
for (int i=1;i<=cnt;i++){
printf("Cnt %d\n",i);
for (int j=1;j<=node[i].num;j++){
printf("num=%d index=%d k=%d step=%d toCnt=%d next=%d\n",j,node[i].index[j],node[i].k[j],node[i].step[j],node[i].to[j],node[i].next[j]);
}
}
}
int main(){
scanf("%d",&n);
sn=sqrt(n);
cnt=n/sn+(n%sn!=0?1:0);
int index=0;
for(int i=1;i<=n;i++){
int temp=0;
index++;
scanf("%d",&temp);
node[(index-1)/sn+1].k[(index-1)%sn+1]=temp;
node[(index-1)/sn+1].index[(index-1)%sn+1]=index;
node[(index-1)/sn+1].num++;
}
calc();
scanf("%d",&m);
for (int i=1;i<=m;i++){
//Arrest();
int order,j;
scanf("%d%d",&order,&j);
j++;
if (order==1){
int icnt=(j-1)/sn+1;
int iindex=(j-1)%sn+1;
int ans=0;
while(iindex!=-1){
//printf("icnt %d iindex %d -> Add %d\n",icnt,iindex,node[icnt].step[iindex]);
ans=ans+node[icnt].step[iindex];
int tindex=iindex;
iindex=node[icnt].next[iindex];
icnt=node[icnt].to[tindex];
}
printf("%d\n",ans);
}else{
int k;
scanf("%d",&k);
calc(j,k);
}
}
return 0;
}