Loj #6281. 数列分块入门 5

区间开方,求和。

分析性质可发现sqrt(0)= 0,sqrt(1) = 1,所以记录每块是否已不能改变。

区分l与r啊。。错了这么个关键字母可不爆零了么。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long ll;
 8 
 9 ll bl[50050],fns[250],v[50050],sum[250];
10 ll n,blo,c,l,r,opt;
11 
12 void check(ll x){
13     for(register int i = (x-1)*blo+1;i <= min(n,x*blo);i++)
14         if(v[i]^0&&v[i]^1)return;
15     fns[x] = 1;
16 }
17 
18 void change(ll l,ll r){
19     ll x,flag;
20     if(bl[l] == bl[r]){
21         flag = true;
22         for(register int i = l;i <= r;i++)if(v[i] > 1){
23             x = sqrt(v[i]);
24             sum[bl[l]] -= v[i]-x;
25             v[i] = x;
26             if(x > 1)flag = false;
27         } if(flag)check(bl[l]); return;
28     }
29     if(!fns[bl[l]]){
30         flag = true;
31         for(register int i = l;i <= bl[l]*blo;i++)if(v[i] > 1){
32             x = sqrt(v[i]);
33             sum[bl[l]] -= v[i]-x;
34             v[i] = x;
35             if(x > 1)flag = false;
36         } if(flag)check(bl[l]);
37     }
38     if(!fns[bl[r]]){
39         flag = true;
40         for(register int i = (bl[r]-1)*blo+1;i <= r;i++)if(v[i] > 1){
41             x = sqrt(v[i]);
42             sum[bl[r]] -= v[i]-x;
43             v[i] = x;
44             if(x > 1)flag = false;
45         } if(flag)check(bl[r]);
46     }
47     for(register int i = bl[l]+1;i < bl[r];i++)if(!fns[i]){
48         flag = true;
49         for(register int j = (i-1)*blo+1;j <= min(n,i*blo);j++)if(v[j] > 1){
50             x = sqrt(v[j]);
51             sum[i] -= v[j]-x;
52             v[j] = x;
53             if(x > 1)flag = false;
54         } if(flag)check(i);
55     }
56 }
57 
58 ll query(ll l,ll r){
59     ll ans = 0;
60     if(bl[l] == bl[r]){
61         for(register int i = l;i <= r;i++)ans += v[i];
62         return ans;
63     }
64     for(register int i = l;i <= bl[l]*blo;i++)ans += v[i];
65     for(register int i = (bl[r]-1)*blo+1;i <= r;i++)ans += v[i];
66     for(register int i = bl[l]+1;i < bl[r];i++)ans += sum[i];
67     return ans;
68 }
69 
70 int main(){
71     scanf("%lld",&n); blo = sqrt(n);
72     for(register int i = 1;i <= n;i++){
73         scanf("%lld",&v[i]);
74         bl[i] = (i-1)/blo+1;
75         sum[bl[i]] += v[i];
76     }
77     for(register int i = 1;i <= bl[n];i++)check(i);
78     for(register int i = 1;i <= n;i++){
79         scanf("%lld%lld%lld%lld",&opt,&l,&r,&c);
80         switch(opt){
81             case 0:change(l,r);break;
82             case 1:printf("%lld\n",query(l,r));break;
83         }
84     }    
85 return 0;
86 }

 

上一篇:[P3806] 【模板】点分治 - 点分治


下一篇:树链剖分