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 }