luogu 2801 教主的魔法
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。
每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
WD巨懒,于是他把这个回答的任务交给了你。
输入输出格式
输入格式:
第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。
输出格式:
对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。
输入输出样例
说明
【输入输出样例说明】
原先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。
思路: 数列分块算法
由于我们要查询区间内大于等于某个数的个数,所以我们要对区间进行排序,修改的时候,如果某个块要加x,那么就给这个块直接标记+x,至于两边零散的部分,可以暴力枚举,暴力修改,修改以后排序。
时间复杂度O(Q*sqrt(n)*logsqrt(n))=O(Q*sqrt(n)logn)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define F(i,a,b) for(int i=a;i<=b;i++) 4 #define D(i,a,b) for(int i=a;i>=b;i--) 5 #define ms(i,a) memset(a,i,sizeof(a)) 6 #define st(x) ((x-1)*B+1) 7 #define ed(x) min(n,x*B) 8 #define bl(x) ((x-1)/B+1) 9 10 int inline read(){ 11 int x=0; char c=getchar(); 12 while (c<'0' || c>'9') c=getchar(); 13 while (c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); 14 return x; 15 } 16 17 int const maxn=1000003; 18 int const maxm=3003; 19 20 int n,m,B,add[maxm],a[maxn],b[maxn],t[maxn]; 21 22 void update(int l,int r,int z){ 23 int x=bl(l); 24 int y=bl(r); 25 if(x==y){ 26 F(i,st(x),ed(x)) t[i]=a[i]; 27 F(i,l,r) t[i]=a[i]=a[i]+z; 28 sort(t+st(x),t+ed(x)+1); 29 F(i,st(x),ed(x)) b[i]=t[i]; 30 }else { 31 F(i,st(x),ed(x)) t[i]=a[i]; 32 F(i,l,ed(x)) t[i]=a[i]=a[i]+z; 33 sort(t+st(x),t+ed(x)+1); 34 F(i,st(x),ed(x)) b[i]=t[i]; 35 F(i,st(y),ed(y)) t[i]=a[i]; 36 F(i,st(y),r) t[i]=a[i]=a[i]+z; 37 sort(t+st(y),t+ed(y)+1); 38 F(i,st(y),ed(y)) b[i]=t[i]; 39 F(i,x+1,y-1) add[i]+=z; 40 } 41 } 42 43 int find(int l,int r,int k,int z){ 44 if(b[r]+add[k]<z) return 0; 45 int s=r; 46 while (l<r){ 47 int mid=(l+r)/2; 48 if( b[mid]+add[k]>=z) r=mid; 49 else l=mid+1; 50 } 51 return s-r+1; 52 } 53 int query(int l,int r,int z){ 54 int x=bl(l); 55 int y=bl(r); 56 int ans=0; 57 if(x==y){ 58 F(i,l,r) if(a[i]+add[x]>=z) ans++; 59 }else { 60 F(i,l,ed(x)) if(a[i]+add[x]>=z) ans++; 61 F(i,st(y),r) if(a[i]+add[y]>=z) ans++; 62 F(i,x+1,y-1) ans+=find(st(i),ed(i),i,z); 63 } 64 return ans; 65 } 66 67 int main(){ 68 n=read(); 69 m=read(); 70 F(i,1,n) a[i]=b[i]=read(); 71 B=(int)sqrt(n); 72 F(i,1,bl(n)) sort(b+st(i),b+ed(i)+1); 73 while (m--){ 74 char s[3]; scanf("%s",s); 75 int x=read(); 76 int y=read(); 77 int z=read(); 78 if(x>y) swap(x,y) ; 79 if(s[0]=='M') { 80 update(x,y,z); 81 }else printf("%d\n",query(x,y,z)); 82 } 83 return 0; 84 }