题意:
给定一个数列,您需要支持以下两种操作:
给[l,r]同加一个数
询问[l,r]中有多少数字大于或等于v
(n<=1000000,m<=3000)
题解
块内排序二分查询
修改就用个数组存整块的修改值
不完整的部分都暴力修改和查询
时间复杂度大概O(Qsqrt(n)logn)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=1001000; 8 int n,m,a[N],b[N],block[N],L[2000],R[2000],cnt[2000],ans,Block; 9 int find(int x,int y){ 10 int l=L[x];int r=R[x]; 11 int tmp=9999999; 12 while(l<=r){ 13 int mid=(l+r)>>1; 14 if(b[mid]>=y){ 15 tmp=mid; 16 r=mid-1; 17 } 18 else l=mid+1; 19 } 20 return max(0,R[x]-tmp+1); 21 } 22 int main(){ 23 scanf("%d%d",&n,&m); 24 Block=sqrt(n); 25 for(int i=1;i<=n;i++){ 26 scanf("%d",&a[i]); 27 b[i]=a[i]; 28 block[i]=(i-1)/Block+1; 29 if(!L[block[i]])L[block[i]]=i; 30 R[block[i]]=i; 31 } 32 for(int i=1;i<=block[n];i++){ 33 sort(b+L[i],b+1+R[i]); 34 } 35 char s[10]; 36 while(m--){ 37 scanf("%s",s); 38 if(s[0]=='A'){ 39 int l,r,c; 40 ans=0; 41 scanf("%d%d%d",&l,&r,&c); 42 for(int i=l;i<=R[block[l]];i++) 43 if(a[i]>=c)ans++; 44 for(int i=L[block[r]];i<=r;i++) 45 if(a[i]>=c)ans++; 46 if(block[l]+1<block[r]) 47 for(int i=block[l]+1;i<=block[r]-1;i++){ 48 ans+=find(i,c-cnt[i]); 49 } 50 printf("%d\n",ans); 51 } 52 else{ 53 int l,r,c; 54 scanf("%d%d%d",&l,&r,&c); 55 if(block[l]+1<block[r]) 56 for(int i=block[l]+1;i<=block[r]-1;i++) 57 cnt[i]+=c; 58 for(int i=l;i<=R[block[l]];i++) 59 a[i]+=c; 60 for(int i=L[block[l]];i<=R[block[l]];i++) 61 b[i]=a[i]; 62 sort(b+L[block[l]],b+1+R[block[l]]); 63 for(int i=L[block[r]];i<=r;i++) 64 a[i]+=c; 65 for(int i=L[block[r]];i<=R[block[r]];i++) 66 b[i]=a[i]; 67 sort(b+L[block[r]],b+1+R[block[r]]); 68 } 69 } 70 return 0; 71 }