题目描述 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 Description###
第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 Description###
对每个“(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
样例输出 Sample Output###
2
3
数据范围及提示 Data Size & Hint###
【输入输出样例说明】
原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。
【数据范围】
对30%的数据,(N≤10^3) ,(Q≤10^3) 。
对100%的数据,(N≤10^6) ,(Q≤3000) ,(1≤W≤10^3) ,(1≤C≤10^9)
之前的一些废话###
明天周六 开心,今晚终于能睡一个好觉了!
题解###
分块,新开一个数组块内排序,修改时暴力修改两端的,并且块内排序,对于中间的块直接打标记。查询时暴力查询两端,勿忘加上标记,对于中间的块在新数组中二分出对应位置即可。
代码###
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> PII;
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=1000010;
int n,q,size,A[maxn],id[maxn],tag[maxn],L[maxn],R[maxn],all,B[maxn],ql,qr,w;
char tp[4];
void bsort(int k)
{
for(int i=L[k];i<=R[k];i++)A[i]+=tag[k],B[i]=A[i];
tag[k]=0;
sort(B+L[k],B+R[k]+1);
}
void update(int l,int r,int w)
{
for(int i=l;i<=R[id[l]];i++)A[i]+=w;
bsort(id[l]);
if(id[l]!=id[r])
{
for(int i=L[id[r]];i<=r;i++)A[i]+=w;
bsort(id[r]);
}
for(int i=id[l]+1;i<=id[r]-1;i++)tag[i]+=w;
}
int query(int l,int r,int w)
{
int x=id[l],y=id[r],cnt=0;
if(x==y){for(int i=l;i<=r;i++)cnt+=(A[i]+tag[x]>=w);return cnt;}
cnt=0;
for(int i=l;i<=R[x];i++)cnt+=(A[i]+tag[x]>=w);
for(int i=L[y];i<=r;i++)cnt+=(A[i]+tag[y]>=w);
for(int i=x+1;i<=y-1;i++)
cnt+=(R[i]-(lower_bound(B+L[i],B+R[i]+1,w-tag[i])-B)+1);
return cnt;
}
int main()
{
n=read();q=read();size=(int)sqrt(n);
for(int i=1;i<=n;i++)A[i]=B[i]=read(),id[i]=(i-1)/size+1;
for(int i=1;i<=n;i+=size)L[++all]=i,R[all]=min(n,i+size-1);
for(int i=1;i<=all;i++)bsort(i);
while(q--)
{
scanf("%s",tp);
ql=read();qr=read();w=read();
if(tp[0]=='M')update(ql,qr,w);
else printf("%d
",query(ql,qr,w));
}
return 0;
}
总结###
分块要写出自己的风格,以此为鉴。