[bzoj3343] 教主的魔法

Description

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

Input

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

Output

       对每一个“A”询问输出一行,仅含一个整数,表示闭区间 [ LR] 内身高大于等于 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

HINT

【输入输出样例说明】
原先5个英雄身高为一、二、三、四、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为一、二、四、五、6,此时[1, 5]间有3个英雄的身高大于等于4。
【数据范围】
对30%的数据, N≤1000, Q≤1000。
对100%的数据, N≤1000000, Q≤3000,1≤ W≤1000,1≤ C≤1,000,000,000。

思路

分块,分红根n块,对于每一个块,构建一个映射数组,转移原数组值,并排序,还有一个标记,储存增值;
对于每次增值操做,对于整块,直接修改标记,对于非整块,暴力修改原数组,并从新构建映射数组;
对于每次查询操做,对于整块,直接在映射数组中二分,对于非整块,暴力枚举;

代码实现

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 const int maxn=1e6+10;
 5 const int maxm=1e3+10;
 6 int n,m,p;
 7 int s[maxn];
 8 int t[maxn],f[maxm];
 9 int search(int l,int r,int x){
10     int ret=0;
11     for(int i=l;i<=r;i++) if(s[i]>=x) ret++;
12     return ret;
13 }
14 int find(int l,int r,int x){
15     int mid,a=r;
16     while(l!=r){
17         mid=l+r>>1;
18         if(t[mid]<x) l=mid+1;
19         else r=mid;
20     }
21     if(t[l]<x) l++;
22     return a-l+1;
23 }
24 void map(int l,int r){
25     for(int i=l;i<=r;i++) t[i]=s[i];
26     std::sort(t+l,t+r+1);
27 }
28 void add(int l,int r,int x){
29     for(int i=l;i<=r;i++) s[i]+=x;
30     map((l-1)/p*p+1,(r+p-1)/p*p);
31 }
32 int main(){
33     scanf("%d%d",&n,&m),p=sqrt(n);
34     for(int i=1;i<=n;i++) scanf("%d",&s[i]);
35     for(int i=1;i<=n/p;i++) map((i-1)*p+1,i*p);
36     if(n%p) map(n/p*p+1,n);
37     int l,r,x,ans;char ch[3];
38     while(m--){
39         scanf("%s%d%d%d",ch,&l,&r,&x);
40         if(ch[0]=='M'){
41             if((l-1)/p==(r-1)/p){add(l,r,x);continue;}
42             if(l%p!=1) add(l,((l-1)/p+1)*p,x);
43             for(int i=(l+1)/p+1;i<=r/p;i++) f[i]+=x;
44             if(r%p) add(r/p*p+1,r,x);
45         }
46         if(ch[0]=='A'){
47             ans=0;
48             if((l-1)/p==(r-1)/p) ans+=search(l,r,x-f[(r-1)/p+1]);
49             else{
50                 if(l%p!=1) ans+=search(l,((l-1)/p+1)*p,x-f[(l-1)/p+1]);
51                 for(int i=(l+1)/p+1;i<=r/p;i++) ans+=find((i-1)*p+1,i*p,x-f[i]);
52                 if(r%p!=0) ans+=search(r/p*p+1,r,x-f[r/p+1]);
53             }
54             printf("%d\n",ans);
55         }
56     }
57     return 0;
58 }

emmmmm,这题数据彷佛很是水,反正我和洛谷里嘉诺巨型方块小数据都拍不过QUQ(固然是他们错啦:P)数组

顺便,这是我第一次写分块,我真的太弱了QUQspa

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息