洛谷P2801 教主的魔法
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给 XMYZ 信息组每个英雄看。于是 NN 个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为 1, 2, \ldots, N1,2,…,N。
每个人的身高一开始都是不超过 10001000 的正整数。教主的魔法每次可以把闭区间 [L, R][L,R](1≤L≤R≤N1≤L≤R≤N)内的英雄的身高全部加上一个整数 WW。(虽然 L=RL=R 时并不符合区间的书写规范,但我们可以认为是单独增加第 L®L® 个英雄的身高)
CYZ、光哥和 ZJQ 等人不信教主的邪,于是他们有时候会问 WD 闭区间 [L, R][L,R] 内有多少英雄身高大于等于 CC,以验证教主的魔法是否真的有效。
WD 巨懒,于是他把这个回答的任务交给了你。
输入格式
第 11 行为两个整数 N, QN,Q。QQ 为问题数与教主的施法数总和。
第 22 行有 NN 个正整数,第 ii 个数代表第 ii 个英雄的身高。
第 33 到第 Q+2Q+2 行每行有一个操作:
若第一个字母为 M,则紧接着有三个数字 L, R, WL,R,W。表示对闭区间 [L, R][L,R] 内所有英雄的身高加上 WW。
若第一个字母为 A,则紧接着有三个数字 L, R, CL,R,C。询问闭区间 [L, R][L,R] 内有多少英雄的身高大于等于 CC。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<set>
#include<string.h>
#include<vector>
#include<set>
#include<cmath>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
const int maxn=1e6+5,SQ=1005;
using namespace std;
int st[SQ],ed[SQ],si[SQ],A[maxn],bel[maxn ];
int read()
{
int ans=0;
char c=getchar();
while(!isdigit(c))
{
c=getchar();
}
while(isdigit(c))
{
ans=ans*10+c-'0';
c=getchar();
}
return ans;
}
void init(int n)
{
int sq=sqrt(n);
for(int i=1;i<=sq;i++)
{
st[i]=n/sq * (i-1)+1;
ed[i]=n/sq * i;
}
ed[sq]=n;
for(int i=1;i<=sq;i++)
for(int j=st[i];j<=ed[i];j++)
bel[j]=i;
for(int i=1;i<=sq;i++)
si[i]=ed[i]-st[i]+1;
}
int mark[SQ];
vector<int>v[SQ];
void update(int b)
{
for(int i=0;i<si[b];i++)
v[b][i]=A[st[b]+i];
sort(v[b].begin(),v[b].end());
}
int main()
{
int n=read(),m=read();
int sq=sqrt(n);
init(n);
for(int i=1;i<=n;i++)
{
A[i]=read();
}
for(int i=1;i<=sq;i++)
for(int j=st[i];j<=ed[i];j++)
v[i].push_back(A[j]);
for(int i=1;i<=sq;i++)sort(v[i].begin(),v[i].end());
while(m--)
{
char o;
scanf(" %c", &o);
int l=read(),r=read(),k=read();
if(o=='M')
{
if(bel[l]==bel[r])
{
for(int i=l;i<=r;i++)
{
A[i]+=k;
}
update(bel[l]);
continue;
}
for(int i=l;i<=ed[bel[l]];i++)A[i]+=k;
for(int i=st[bel[r]];i<=r;i++)A[i]+=k;
update(bel[l]);
update(bel[r]);
for(int i=bel[l]+1;i<bel[r];i++)mark[i]+=k;
}
else
{
int tot=0;
if(bel[l]==bel[r])
{
for(int i=l;i<=r;i++)
if(A[i]+mark[bel[l]]>=k)tot++;
printf("%d\n",tot);
continue;
}
for(int i=l;i<=ed[bel[l]];i++)
if(A[i]+mark[bel[l]]>=k)tot++;
for(int i=st[bel[r]];i<=r;i++)
if(A[i]+mark[bel[r]]>=k)tot++;
for(int i=bel[l]+1;i<bel[r];i++)
{
tot+=v[i].end()-lower_bound(v[i].begin(),v[i].end(),k-mark[i]);
}
printf("%d\n",tot);
}
}
return 0;
}