LOJ #6279. 数列分块入门 3
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 c 的前驱(比其小的最大元素)。
先在每个块内排序,然后残块暴力,整块lower_bound。
指针形式运用lower_bound一定要小心啊啊啊 (调了1h+)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<vector> 5 #include<cstring> 6 #include<cmath> 7 #define pb push_back 8 #define lb lower_bound 9 #define val(i) (v[i]+atag[bl[i]]) 10 using namespace std; 11 12 const int Maxn = 50005*2; 13 int v[Maxn],atag[Maxn],bl[Maxn]; 14 int opt,l,r,c,n,blo; 15 vector<int> V[Maxn]; 16 17 void reset(int x){ 18 for(int i = (x-1)*blo+1;i <= min(n,x*blo);i++) 19 V[x][(i-1)%blo] = v[i]; 20 sort(V[x].begin(),V[x].end()); 21 } 22 23 void change(int l,int r,int c){ 24 if(l > r)return; 25 if(bl[l] == bl[r]){ 26 for(int i = l;i <= r;i++)v[i] += c; 27 reset(bl[l]); return; 28 } 29 for(int i = l;i <= bl[l]*blo;i++)v[i] += c;reset(bl[l]); 30 for(int i = (bl[r]-1)*blo+1;i <= r;i++)v[i] += c;reset(bl[r]); 31 for(int i = bl[l]+1;i < bl[r];i++)atag[i] += c; 32 } 33 34 int query(int l,int r,int c){ 35 if(l > r)return -1; 36 int ans = -1; 37 if(bl[l] == bl[r]){ 38 for(int i = l;i <= r;i++) 39 if(ans < val(i)&&val(i) < c)ans = val(i); 40 return ans; 41 } 42 for(int i = l;i <= bl[l]*blo;i++) 43 if(ans < val(i)&&val(i) < c)ans = val(i);// 44 for(int i = (bl[r]-1)*blo+1;i <= r;i++) 45 if(ans < val(i)&&val(i) < c)ans = val(i);// 46 for(int i = bl[l]+1;i < bl[r];i++){ 47 vector<int>::iterator x = lb(V[i].begin(),V[i].end(),c-atag[i]); 48 if(x == V[i].begin())continue;x--; 49 while(x != V[i].begin()&&*x >= c-atag[i])x--; 50 if(ans-atag[i] < *x&&*x < c-atag[i])ans = *x+atag[i]; 51 } 52 return ans; 53 } 54 55 int main(){ 56 scanf("%d",&n);blo = sqrt(n); 57 for(int i = 1;i <= n;i++){ 58 scanf("%d",&v[i]); 59 bl[i] = (i-1)/blo+1; 60 V[bl[i]].pb(v[i]); 61 } 62 for(int i = 1;i <= bl[n];i++) 63 sort(V[i].begin(),V[i].end()); 64 for(int i = 1;i <= n;i++){ 65 scanf("%d%d%d%d",&opt,&l,&r,&c); 66 if(opt == 1)printf("%d\n",query(l,r,c)); 67 if(opt == 0)change(l,r,c); 68 } 69 return 0; 70 }