教主的魔法
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给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 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4
样例输出
2
3
我也懒,所以直接把题面粘过来了
我当时一看这玩意,这不纯纯板子吗,然后就去打了,然后…………
大唐盛世…………
第一个错点,忘分块了
分完块,就T了
后面问了wlesq,说是二分,实际上T了之后也想过二分,但但想的是查询的时候,排一遍序,再用二分(那还不如直接遍历)
然后就卡住了,后面瞟了一眼题解,看了个大概,好像是再修改和分块的时候,排序,且只用给散块排序(因为整块同加同减,不会变顺序),然后就开搞了
然后就又卡在一个问题上,排完序后数不对应,且没啥好方法,所以索性就这么搞了
struct node{
int num;
int id;
}a[1200000];
bool cmp1(const node&a,const node&b){
return a.num<b.num;
}
bool cmp2(const node&a,const node&b){
return a.id<b.id;
}
sort(a+l[p],a+1+r[p],cmp2);
for(int i=x;i<=y;i++){
a[i].num+=z;
}
sort(a+l[p],a+1+r[p],cmp1);
先按序号将数排回来,修改完后排回去,就可以解决了
后面就没什么大问题了
唐氏错误
1.演员二分
while(le<=ri){
int mid=(le+ri)/2;
if(a[mid].num+lazy[i]<=z){
le=mid+1;ans1=r[i]-mid+1;
}
else{
ri=mid-1;
}
}//错的
while(le<=ri){
int mid=(le+ri)/2;
if(a[mid].num+lazy[i]<z){
le=mid+1;
}
else{
ri=mid-1;ans1=r[i]-mid+1;
}
}//正确的
2.数组开小(少开了1)
3.查询时排序
还有就是排序的时候是
sort(a+l[q],a+1+r[q]);
而不是
sort(a+l[q]+1,a+1+r[q]);
可以类比于
sort(a+1,a+1+n);
会发现,左边界是1,右边界是n
fixed:今天Elaina_0查题解时发现hack代码,然后我去试了试,然后寄了,后面发现,再修改时并未将区间内数组按编号排回去,导致查询出锅,再查询前加上按编号排序就好了(查完不用归位,修改时就自动排了)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int lazy[1200000];
int l[1200000],r[1200000];
int vis[1200000];
struct node{
int num;
int id;
}a[1200000];
bool cmp1(const node&a,const node&b){
return a.num<b.num;
}
bool cmp2(const node&a,const node&b){
return a.id<b.id;
}
int n,m;
void div(){
int sq=sqrt(n);
for(int i=1;i<=sq;i++){
l[i]=(i-1)*sq+1;
r[i]=sq*i;
}
if(r[sq]<n){
sq++;
l[sq]=r[sq-1]+1;
r[sq]=n;
}
for(int i=1;i<=sq;i++){
sort(a+l[i],a+r[i]+1,cmp1);
for(int j=l[i];j<=r[i];j++){
vis[j]=i;
}
}
}
void add(int x,int y,int z){
int p=vis[x],q=vis[y];
if(p==q){
sort(a+l[p],a+1+r[p],cmp2);
for(int i=x;i<=y;i++){
a[i].num+=z;
}
sort(a+l[p],a+1+r[p],cmp1);
}
else {
sort(a+l[p],a+1+r[p],cmp2);
for(int i=x;i<=r[p];i++){
a[i].num+=z;
}
sort(a+l[p],a+1+r[p],cmp1);
for(int i=p+1;i<q;i++){
lazy[i]+=z;
}
sort(a+l[q],a+1+r[q],cmp2);
for(int i=l[q];i<=y;i++){
a[i].num+=z;
}
sort(a+l[q],a+1+r[q],cmp1);
}
}
int query(int x,int y,int z){
int ans=0;
int p=vis[x],q=vis[y];
if(p==q){
sort(a+l[q],a+1+r[q],cmp2);
for(int i=x;i<=y;i++){
if(a[i].num+lazy[p]>=z) ans++;
}
// sort(a+l[q],a+1+r[q],cmp1);
}
else {
sort(a+l[p],a+1+r[p],cmp2);
for(int i=x;i<=r[p];i++){
if(a[i].num+lazy[p]>=z) ans++;
}
// sort(a+l[p],a+1+r[p],cmp1);
int ans1=0;
for(int i=p+1;i<q;i++){
int le=l[i],ri=r[i];
while(le<=ri){
int mid=(le+ri)/2;
if(a[mid].num+lazy[i]<z){
le=mid+1;
}
else{
ri=mid-1;ans1=r[i]-mid+1;
}
}
ans+=ans1;ans1=0;
}
sort(a+l[q],a+1+r[q],cmp2);
for(int i=l[q];i<=y;i++){
if(a[i].num+lazy[q]>=z) ans++;
}
// sort(a+l[q],a+1+r[q],cmp1);
}
return ans;
}
int main(){
int x,y,z;
string s;
cin>>n>>m;
for(int i=1;i<=n;i++) {cin>>a[i].num;a[i].id=i;}
div();
for(int i=1;i<=m;i++){
cin>>s;
if(s=="M"){
cin>>x>>y>>z;
add(x,y,z);
}
else {
cin>>x>>y>>z;
cout<<query(x,y,z)<<endl;
}
}
}
/*
10 5
39 56 58 26 89 11 86 31 84 21
M 6 8 80
M 1 2 90
A 1 1 88
*/