教主的魔法[分块+二分]
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给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
题解
分块+排序+二分
首先我们把这个题目拆开来看:
(1)要询问或给(l,r)加一个值
(2)在(l,r)区间的值是不定值,还要求的是大于等于k的数有多少
由(1)–>得尝试分块和分块的加法标记
由(2)–>得我们可以事先处理好每一块的顺序,然后找到大于等于k的第一个数,就能求出每一块的贡献值了–>sort+vector
要注意的是,当l,r处在两个不完整的块,暴力加上在排序就ok了
ps:我用了stl,洛谷要开o2,或者考虑手打二分
// luogu-judger-enable-o2 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<vector> using namespace std; int n,m,tmp; int ch[1000005],bl[1000005],addx[1000005],l[1000005],r[1000005]; vector<int>ve[5005]; int read() { int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } void build() { for(int i=1;i<=tmp;i++) { l[i]=(i-1)*tmp+1;r[i]=tmp*i; } r[tmp]=n; for(int i=1;i<=n;i++) { bl[i]=(i-1)/(tmp)+1; ve[bl[i]].push_back(ch[i]); } for(int i=1;i<=bl[n];i++) sort(ve[i].begin(),ve[i].end()); /* for(int i=1;i<=bl[n];i++) for(int j=0;j<ve[i].size();j++) cout<<ve[i][j]<<' ';*/ } void change(int x) { ve[x].clear(); for(int i=l[x];i<=r[x];i++) ve[x].push_back(ch[i]); sort(ve[x].begin(),ve[x].end()+1); } void add(int x,int y,int k) { if(bl[x]==bl[y]) for(int i=x;i<=y;i++)ch[i]+=k; else { for(int i=x;i<=r[bl[x]];i++)ch[i]+=k; for(int i=l[bl[y]];i<=y;i++)ch[i]+=k; } change(bl[x]);change(bl[y]); for(int i=bl[x]+1;i<=bl[y]-1;i++) { addx[i]+=k; } } int query(int x,int y,int k) { int ans=0; // cout<<x<<' '<<y<<' '<<k<<endl; if(bl[x]==bl[y])for(int i=x;i<=y;i++){if(ch[i]+addx[bl[x]]>=k)ans++;} else { for(int i=x;i<=r[bl[x]];i++){if(ch[i]+addx[bl[x]]>=k)ans++;} for(int i=l[bl[y]];i<=y;i++){if(ch[i]+addx[bl[y]]>=k)ans++;} } // cout<<ans<<endl; for(int i=bl[x]+1;i<=bl[y]-1;i++) { // cout<<".."<<endl; int xx=k-addx[i]; int sum=lower_bound(ve[i].begin(),ve[i].end(),xx)-ve[i].begin(); //cout<<sum<<endl; ans+=tmp-sum; // cout<<ans<<endl; } return ans; } int main() { n=read();m=read();tmp=sqrt(n);if(tmp*tmp<n)tmp++; for(int i=1;i<=n;i++) { ch[i]=read(); } build(); for(int i=1;i<=m;i++) { char f;int x,y,z; cin>>f;x=read();y=read();z=read(); if(f=='M')add(x,y,z); else printf("%d\n",query(x,y,z)); } return 0; }