[HNOI2010] 弹飞绵羊
昨天做分块(Ynoi)上瘾了,然后就看到了这道题......
LCT当然是正解,但是考场上如果能想出分块的做法当然是要写分块了啊。
毕竟我太弱了,LCT容易写挂。
分块多好写啊,只有50行.....
可以把这道题看作是经典数据结构题。
经典的数据结构题都有查询和修改两种操作。
对于这道题,如果直接暴力模拟,查询很慢,是O(n)的;但是修改很快,是O(1)的。
如果每次修改之后都预处理出所有点的答案,那么修改就会很慢,是O(n);但是查询就很快了,达到O(1)。
在洛谷上看到了一句话:分块的作用就是平衡查询和修改的时间复杂度。
我们分块之后,可以处理出如果进到块里某个点,会跳几次才能出块,出块之后会跳到哪里。
这样对于每次询问,我们跳sqrt(n)次就行了。
对于每次修改,我们只需要重新处理被修改的点所在的块,也是O(sqrt n)。
这样查询和修改的复杂度就平衡了.....真和谐。
1 #include<cstdio> 2 #include<cmath> 3 4 int n,m,sz; 5 int bl[200005],l[635],r[635]; 6 int k[200005],to[200005],cnt[200005]; 7 8 void reset(int id) 9 { 10 for(int i=r[id];i>=l[id];i--) 11 { 12 if(i+k[i]>r[id])to[i]=i+k[i],cnt[i]=1; 13 else to[i]=to[i+k[i]],cnt[i]=cnt[i+k[i]]+1; 14 } 15 } 16 17 int main() 18 { 19 scanf("%d",&n); 20 for(int i=0;i<n;i++)scanf("%d",&k[i]); 21 sz=(int)sqrt(n*2); 22 for(int i=0;i<n;i++)bl[i]=i/sz; 23 for(int i=0;i<=bl[n-1];i++) 24 l[i]=i*sz,r[i]=l[i]+sz-1; 25 r[bl[n-1]]=n-1; 26 for(int i=0;i<=bl[n-1];i++)reset(i); 27 scanf("%d",&m); 28 for(int i=1;i<=m;i++) 29 { 30 int op,p,ck; 31 scanf("%d%d",&op,&p); 32 if(op==1) 33 { 34 int ans=0; 35 while(p<n) 36 { 37 ans+=cnt[p]; 38 p=to[p]; 39 } 40 printf("%d\n",ans); 41 } 42 if(op==2) 43 { 44 scanf("%d",&ck); 45 k[p]=ck; 46 reset(bl[p]); 47 } 48 } 49 return 0; 50 }
忘打 r[bl[n-1]]=n-1; 没一遍A......