[HNOI2010] 弹飞绵羊

洛谷 P3203 传送门

昨天做分块(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
",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......

原文地址:https://www.cnblogs.com/cervusy/p/9994036.html