「BZOJ3343」教主的魔法(分块+二分查找)

题意:

给定一个数列,您需要支持以下两种操作:
给[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++)sort(b+L[i],b+1+R[i]);
33     char s[10];
34     while(m--){
35         scanf("%s",s);
36         if(s[0]=='A'){
37             int l,r,c;
38             ans=0;
39             scanf("%d%d%d",&l,&r,&c);
40             if(block[l]==block[r]){
41                 for(int i=l;i<=r;i++)if(a[i]+cnt[block[i]]>=c)ans++;
42                 printf("%d\n",ans);
43                 continue;
44             }
45             for(int i=l;i<=R[block[l]];i++)if(a[i]+cnt[block[i]]>=c)ans++;
46             for(int i=L[block[r]];i<=r;i++)if(a[i]+cnt[block[i]]>=c)ans++;
47             if(block[l]+1<block[r])
48                 for(int i=block[l]+1;i<=block[r]-1;i++)ans+=find(i,c-cnt[i]);
49             printf("%d\n",ans);
50         }
51         else{
52             int l,r,c;
53             scanf("%d%d%d",&l,&r,&c);
54             if(block[l]+1<block[r])
55                 for(int i=block[l]+1;i<=block[r]-1;i++)cnt[i]+=c;
56             for(int i=l;i<=R[block[l]];i++)a[i]+=c;
57             for(int i=L[block[l]];i<=R[block[l]];i++)b[i]=a[i];
58             sort(b+L[block[l]],b+1+R[block[l]]);
59             for(int i=L[block[r]];i<=r;i++)a[i]+=c;
60             for(int i=L[block[r]];i<=R[block[r]];i++)b[i]=a[i];
61             sort(b+L[block[r]],b+1+R[block[r]]);
62         }
63     }
64     return 0;
65 }

 

posted @ 2018-08-15 11:42  Xu-daxia  阅读(109)  评论(0编辑  收藏  举报