BZOJ 2002: [Hnoi2010]Bounce 彈飛綿羊

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

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

Sample Output

2
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;
} 


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