LOJ #6278. 数列分块入门 2

hzwer tql!

渐渐找到了分块的套路。

给出一个长为  n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 c*c 的元素个数。

残块先在原数组上暴力,然后拿原数组更新块数组(效率高于结构体存id!),整块就标记。

code:

 1 #include<iostream>
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<vector>
 6 #define pb push_back
 7 #define lb lower_bound
 8 using namespace std;
 9 
10 const int Maxn = 50005; 
11 
12 vector<int> V[Maxn];
13 int bl[Maxn],v[Maxn],atag[Maxn];
14 int n,blo,l,r,opt,c;
15 
16 void reset(int x){
17     for(int i = (x-1)*blo+1;i <= min(n,x*blo);i++)
18         V[x][(i-1)%blo] = v[i];
19     sort(V[x].begin(),V[x].end());
20 } 
21 
22 void add(int l,int r,int c){
23     if(bl[l] == bl[r]){
24         for(int i = l;i <= r;i++)v[i] += c;
25         reset(bl[r]);return;
26     }
27     for(int i = l;i <= min(n,bl[l]*blo);i++)v[i] += c;reset(bl[l]);
28     for(int i = (bl[r]-1)*blo+1;i <= r;i++)v[i] += c;reset(bl[r]);
29     for(int i = bl[l]+1;i < bl[r];i++)atag[i] += c;
30 }
31 
32 int ask(int l,int r,int c2){
33     if(l > r)return 0;
34     int cnt = 0;
35     if(bl[l] == bl[r]){
36         for(int i = l;i <= r;i++)if(v[i]+atag[bl[i]] < c2)cnt++;
37         return cnt;
38     }
39     for(int i = l;i <= min(bl[l]*blo,n);i++)
40         if(v[i]+atag[bl[i]] < c2)cnt++;
41     for(int i = (bl[r]-1)*blo+1;i <= min(r,n);i++)
42         if(v[i]+atag[bl[i]] < c2)cnt++;
43     for(int i = bl[l]+1;i < bl[r];i++)
44         cnt += lb(V[i].begin(),V[i].end(),c2-atag[i])-V[i].begin();
45     return cnt;
46 }
47 
48 int main(){
49     scanf("%d",&n);blo = sqrt(n);
50     for(int i = 1;i <= n;i++){
51         scanf("%d",&v[i]);
52         bl[i] = (i-1)/blo+1;
53         V[bl[i]].pb(v[i]);
54     }
55     for(int i = 1;i <= bl[n];i++)sort(V[i].begin(),V[i].end());
56     for(int i = 1;i <= n;i++){
57         scanf("%d%d%d%d",&opt,&l,&r,&c);
58         if(opt)printf("%d\n",ask(l,r,c*c));
59         else add(l,r,c);
60     }
61 return 0;
62 }

猜你喜欢

转载自www.cnblogs.com/Wangsheng5/p/11780736.html