bzoj2002: [Hnoi2010]Bounce 弹飞绵羊 [分块][LCT]

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

直接模拟肯定超时
考虑分块优化
(其实是不会lct辣!)
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<cmath>
 5 using namespace std;
 6 
 7 inline int read(){
 8     char ch;
 9     int re=0;
10     bool flag=0;
11     while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
12     ch=='-'?flag=1:re=ch-'0';
13     while((ch=getchar())>='0'&&ch<='9')  re=re*10+ch-'0';
14     return flag?-re:re;
15 }
16 
17 const int maxn=200001;
18 
19 int n,m;
20 //b[][1]跳到下一分块中的位置 
21 //b[][0]跳到下一分块需要的步数 
22 //c[]分块序号 
23 int a[maxn],b[maxn][2],c[maxn];
24 
25 int main(){
26     //freopen("temp.in","r",stdin);
27     n=read();
28     for(int i=0;i<n;i++)  a[i]=read();
29     for(int i=0,v=1,h=(int)sqrt(n);i<n;i++){
30         c[i]=v;
31         if((i+1)%h==0)  v++;
32     }
33     for(int i=n-1;i>=0;i--){
34         //跳出分块或弹飞 
35         if(i+a[i]>n-1||c[i+a[i]]!=c[i])  b[i][1]=i+a[i];
36         else  b[i][1]=b[i+a[i]][1];
37         //记录多少步跳出分块 
38         if(c[i+a[i]]!=c[i])  b[i][0]=1;
39         else  b[i][0]=b[i+a[i]][0]+1;
40     }
41     m=read();
42     int opt,pos,num,ans;
43     while(m--){
44         opt=read();
45         if(opt==1){
46             pos=read();
47             ans=0;
48             while(pos<=n-1){
49                 ans+=b[pos][0];
50                 pos=b[pos][1];
51             }
52             if(ans==0)  puts("1");
53             else  printf("%d\n",ans);
54         }
55         else{
56             pos=read();  num=read();
57             a[pos]=num;
58             if(pos+num>n-1||c[pos+num]!=c[pos])  b[pos][1]=pos+num;
59             else  b[pos][1]=b[pos+num][1];
60             if(c[pos+num]!=c[pos])  b[pos][0]=1;
61             else  b[pos][0]=b[pos+num][0]+1;
62             for(int i=pos-1;i>=0;i--){
63                 if(c[i]!=c[pos])  break;
64                 if(i+a[i]<=n-1&&c[i+a[i]]==c[i])  b[i][1]=b[i+a[i]][1];
65                 if(c[i+a[i]]==c[i])  b[i][0]=b[i+a[i]][0]+1;
66             }
67         }
68     }
69     return 0;
70 }

 

posted @ 2017-07-10 12:24  ZYBGMZL  阅读(84)  评论(0编辑  收藏