c++之路进阶——bzoj3343(教主的魔法)
F.A.Qs | Home | Discuss | ProblemSet | Status | Ranklist | Contest | ModifyUser gryz2016 | Logout | 捐赠本站 |
---|
Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入、输出语句及数据类型及范围,避免无谓的RE出现。
3343: 教主的魔法
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 711 Solved: 309
[Submit][Status][Discuss]
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。
Source
题解:
个人用块状链表写的,
对于首尾块用暴力更新,中间的加add标志。
第一次提交超时,很奇怪,然后发现循环套快排了,我去,坑了我2h。。。
代码:
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #define maxn 1000010 5 #define logmaxn 100010 6 7 using namespace std; 8 9 int a[maxn],up[logmaxn],belong[maxn],l[logmaxn],r[logmaxn],b[maxn],sum; 10 int n,m,sqrp,gs,ans; 11 int main() 12 { 13 scanf("%d%d",&n,&m); 14 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 15 sqrp=sqrt(n); 16 if (n%sqrp) gs=n/sqrp+1; 17 else gs=n/sqrp; 18 for (int i=1;i<=gs;i++) 19 l[i]=(i-1)*sqrp+1,r[i]=i*sqrp; 20 r[gs]=n; 21 for (int i=n;i>0;i--) 22 belong[i]=(i-1)/sqrp+1; 23 for (int i=1;i<=gs;i++) 24 { 25 for (int j=l[i];j<=r[i];j++) 26 b[j]=a[j]; 27 sort(b+l[i],b+r[i]+1); 28 } 29 for (int i=1;i<=m;i++) 30 { 31 char ch[1]; 32 int ll,rr,x; 33 scanf("%s%d%d%d",ch,&ll,&rr,&x); 34 int lll=belong[ll]; 35 int rrr=belong[rr]; 36 switch(ch[0]) 37 { 38 case 'M': 39 if (lll==rrr) 40 { 41 for (int j=ll;j<=rr;j++) 42 a[j]=a[j]+x; 43 for (int j=l[lll];j<=r[lll];j++) 44 b[j]=a[j]; 45 sort(b+l[lll],b+r[lll]+1); 46 } 47 else 48 { 49 for (int j=ll;j<=r[lll];j++) 50 a[j]+=x; 51 for (int j=l[lll];j<=r[lll];j++) 52 b[j]=a[j]; 53 sort(b+l[lll],b+r[lll]+1); 54 for (int j=l[rrr];j<=rr;j++) 55 a[j]+=x; 56 for (int j=l[rrr];j<=r[rrr];j++) 57 b[j]=a[j]; 58 sort(b+l[rrr],b+r[rrr]+1); 59 for (int j=lll+1;j<rrr;j++) 60 up[j]+=x; 61 } 62 break; 63 case 'A': 64 if (lll==rrr) 65 { 66 for (int j=ll;j<=rr;j++) 67 if (a[j]+up[lll]>=x) ans++; 68 } 69 else 70 { 71 for (int j=ll;j<=r[lll];j++) 72 if (a[j]+up[lll]>=x) ans++; 73 74 for (int j=l[rrr];j<=rr;j++) 75 if (a[j]+up[rrr]>=x) ans++; 76 for (int j=lll+1;j<=rrr-1;j++) 77 { 78 sum=lower_bound(b+l[j],b+r[j]+1,x-up[j])-b; 79 ans+=r[j]+1-sum; 80 } 81 } 82 printf("%d\n",ans); 83 ans=0; 84 break; 85 } 86 } 87 return 0; 88 }
数据生成器:
#include<iostream> #include<cstdlib> #include<cstdio> #include<time.h> using namespace std; int main() { srand(time(0)); freopen("magic.txt","w",stdout); int n=1000000,q=3000; cout<<n<<' '<<q<<endl; for(int i=1;i<=n;i++) cout<<rand()%1000+1<<endl; cout<<endl; for(int i=1;i<=q;i++) { int f=rand()%2; int l=rand()%n+1,r=rand()%n+1; if(r<l)swap(l,r); if(f)cout<<'A'<<' '<<l<<' '<<r<<' '<<rand()%1000<<endl; else cout<<'M'<<' '<<l<<' '<<r<<' '<<rand()%1000000000<<endl; } return 0; }