码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3343] 教主的魔法

时间:2017-12-18 00:01:07      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:pre   标记   print   -o   lan   数组   代码实现   desc   scanf   

Description

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、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个英雄身高为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

[bzoj3343] 教主的魔法

标签:pre   标记   print   -o   lan   数组   代码实现   desc   scanf   

原文地址:http://www.cnblogs.com/J-william/p/8053426.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!