【bzoj3343 教主的魔法】

Description

  教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。
  每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)
  CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
  WD巨懒,于是他把这个回答的任务交给了你。

Input

  第1行为两个整数N、Q。Q为问题数与教主的施法数总和。
  第2行有N个正整数,第i个数代表第i个英雄的身高。
  第3到第Q+2行每行有一个操作:
  若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
  若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。

Output

  对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。

Sample Input

  5 3
  1 2 3 4 5
  A 1 5 4
  M 3 5 1
  A 1 5 4

Sample Output

  2
  3

题解:

  分块。对每个块中排序,于是询问就可以二分了。

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 using namespace std;
 8 int n,Q,m,blo;
 9 int a[1000005],b[1000005],bl[1000005],add[1000005];
10 inline void init(int x){
11     int L=blo*(x-1)+1,R=min(blo*x,n);
12     for(int i=L;i<=R;i++){
13         b[i]=a[i];
14     }
15     sort(b+L,b+R+1);
16 }
17 inline int find(int x,int v){
18     return min(n,blo*x)+1-(lower_bound(b+(x-1)*blo+1,b+min(n,blo*x)+1,v)-b);
19 }
20 inline int query(int l,int r,int v){
21     int sum=0;
22     if(bl[l]==bl[r]){
23         for(int i=l;l<=r;i++){
24             if(a[i]+add[bl[i]]>=v)    sum++;
25         }
26     }
27     else{
28         for(int i=l;i<=bl[l]*blo;i++)
29             if(a[i]+add[bl[i]]>=v)    sum++;
30         for(int i=(bl[r]-1)*blo+1;i<=r;i++)    
31             if(a[i]+add[bl[i]]>=v)    sum++;
32     }
33     for(int i=bl[l]+1;i<=bl[r]-1;i++)
34         sum+=find(i,v-add[i]);
35     return sum;
36 }
37 inline void update(int l,int r,int v){
38     if(bl[l]==bl[r]){
39         for(int i=l;i<=r;i++)
40             a[i]+=v;
41     }
42     else{
43         for(int i=l;i<=bl[l]*blo;i++)    a[i]+=v;
44         for(int i=(bl[r]-1)*blo+1;i<=r;i++)    a[i]+=v;
45     }
46     init(bl[l]);init(bl[r]);
47     for(int i=bl[l]+1;i<=bl[r]-1;i++)    add[i]+=v;
48 }
49 int main(){
50     char ch[5];
51     int x,y,v;
52     scanf("%d%d",&n,&Q);
53     blo=(int)sqrt(n);
54     for(int i=1;i<=n;i++){
55         scanf("%d",&a[i]);
56         bl[i]=(i-1)/blo+1;
57     }
58     if(n%blo==0)    m=n/blo;
59     else    m=n/blo+1;
60     for(int i=1;i<=m;i++)    init(i);
61     while(Q--){
62         scanf("%s%d%d%d",ch,&x,&y,&v);
63         if(ch[0]=='M')    update(x,y,v);
64         else    printf("%d\n",query(x,y,v));
65     }
66     return 0;
67 }

 

 

posted @ 2017-12-05 21:25  LittleOrange  阅读(166)  评论(0编辑  收藏  举报