loj#6281. 数列分块入门 5

#6281. 数列分块入门 5

题目:传送门 

简要题意:

   给出一个长为 n 的数列,以及 n 个操作,操作涉及区间开方,区间求和。


题解:

   怎么说...这道题loj的数据有点水。

   和bzoj花神游历各国是一样的...但是loj没有卡掉不完全优化的代码。

   基础操作就不说了(同分块4),主要讲优化吧:

   不难发现,因为开方后我们是向下取整的,那么如果一直开方下去,整个序列一定会变成0或1。那么如果当前区间都是0或1就没有操作的必要了嘛。

   讲到这里思路就已经很清晰了,但是一开始的时候本蒟蒻并没有优化头尾的块,依然在loj AC了...bzoj就挂了,事实证明:暴力加优化才是分块真正的难点!


代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long LL;
 8 LL n,m,a[110000],sum[110000];
 9 LL block,pos[110000];
10 bool v[110000];
11 void reset(LL x)
12 {
13     if(v[x])return ;
14     v[x]=1;sum[x]=0;
15     for(int i=(x-1)*block+1;i<=x*block;i++)
16     {
17         a[i]=sqrt(a[i]);sum[x]+=a[i];
18         if(a[i]>1)v[x]=0;
19     }
20 }
21 void update(LL l,LL r)
22 {
23     if(!v[pos[l]])
24     {
25         for(int i=l;i<=min(pos[l]*block,r);i++)
26         {
27             sum[pos[l]]-=a[i];
28             a[i]=sqrt(a[i]);
29             sum[pos[l]]+=a[i];
30         }
31         v[pos[l]]=1;for(int i=(pos[l]-1)*block+1;i<=pos[l]*block;i++)if(a[i]>1)v[pos[l]]=0;
32     }
33     if(pos[l]!=pos[r])
34     {
35         if(!v[pos[r]])
36         {
37             for(int i=(pos[r]-1)*block+1;i<=r;i++)
38             {
39                 sum[pos[r]]-=a[i];
40                 a[i]=sqrt(a[i]);
41                 sum[pos[r]]+=a[i];
42             }
43             v[pos[r]]=1;for(int i=(pos[r]-1)*block;i<=pos[r]*block;i++)if(a[i]>1)v[pos[r]]=0;
44         }
45     }
46     for(int i=pos[l]+1;i<=pos[r]-1;i++)reset(i);
47 }
48 void sol(LL l,LL r)
49 {
50     LL ans=0;
51     for(int i=l;i<=min(pos[l]*block,r);i++)ans+=a[i];
52     if(pos[l]!=pos[r])
53         for(int i=(pos[r]-1)*block+1;i<=r;i++)
54             ans+=a[i];
55     for(int i=pos[l]+1;i<=pos[r]-1;i++)ans+=sum[i];
56     printf("%lld
",ans);
57 }
58 int main()
59 {
60     memset(v,false,sizeof(v));
61     scanf("%lld",&n);
62     for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
63     block=sqrt(n);
64     for(int i=1;i<=n;i++)
65     {
66         pos[i]=(i-1)/block+1;
67         sum[pos[i]]+=a[i];
68     }
69     for(int i=1;i<=n;i++)
70     {
71         LL opt,l,r,c;scanf("%lld%lld%lld%lld",&opt,&l,&r,&c);
72         if(opt==0)update(l,r);
73         else sol(l,r);
74     }
75     return 0;
76 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8580640.html