n个洞1~n,每个洞有一个power,a1~an。把球扔到第i个洞,它会蹦到第i+ai个洞去(一直往后蹦,直到n以外)。有m次操作,分为两种,0是询问把求扔到某个洞,最后能到达哪个洞以及会蹦多少次,1是修改某个洞的power。
这是在CF上一篇讲数据结构的博客上看到的题,学到了一个新的姿势。。方法是分块维护,每块的大小是sqrt(n)。对每个洞,维护它能在本块内蹦多少次和最后到达块内哪个洞。这样,每次操作不管是查询还是修改,它的复杂度都是sqrt(n),卡着时限过了这道题。。
#include <iostream>
#include <stdio.h>
#include <string>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn=100010;
int power[maxn];
int last_hole[maxn];
int num[maxn];
int group[maxn];
int n,m;
void fun(int pos){
if(group[pos]!=group[pos+power[pos]]){
num[pos]=1;
last_hole[pos]=pos;
return;
}
num[pos]=num[pos+power[pos]]+1;
last_hole[pos]=last_hole[pos+power[pos]];
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",&power[i]);
}
int SQRT=sqrt(n);
int cnt=-1;
group[0]=1;
for(int i=1;i<=n;i++){
cnt++;
if(cnt==SQRT){
group[i]=group[i-1]+1;
cnt=0;
}else{
group[i]=group[i-1];
}
}
group[0]=0;
//计算本组最后一个洞
//计算到下组要跳几次
for(int i=n;i>=1;i--){
fun(i);
}
for(int i=1;i<=m;i++){
int op,a,b;
scanf("%d",&op);
if(op){
scanf("%d",&a);
int last=a;
int cnt=0;
while(1){
cnt+=num[last];
last=last_hole[last];
if(last+power[last]>n)break;
last+=power[last];
}
printf("%d %d\n",last,cnt);
}else{
scanf("%d%d",&a,&b);
power[a]=b;
while(1){
fun(a);
a--;
if(group[a]!=group[a+1])break;
}
}
}
return 0;
}