[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行每行有一个操作:
(1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
(2) 若第一个字母为“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
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4
Sample Output
2
3
3
HINT
【输入输出样例说明】
原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、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)
顺便,这是我第一次写分块,我真的太弱了QUQ