#分块,二分#洛谷 2801 教主的魔法

题目

支持两个操作:

  1. 在区间 [ l ∼ r ] [l\sim r] [lr]增加 x x x
  2. 在区间 [ l ∼ r ] [l\sim r] [lr]查询 ≥ x \geq x x的个数

分析

第二个操作太困难了,所以说尝试分块,在块内排序,二分答案,块外暴力,对于块内的区间加,可以加上懒标记,二分时减掉这个数


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
using namespace std;
const int N=1000001;
int pos[N],l[N],r[N],b[N],a[N],lazy[N],n,bk,m,cnt; 
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
inline void update(int x,int y,int z){
    if (pos[x]==pos[y]){
        for (rr int i=l[pos[x]];i<=r[pos[y]];++i) a[i]+=z*(i>=x&&i<=y),b[i]=a[i];
        sort(b+l[pos[x]],b+1+r[pos[y]]);
        return;
    }
    for (rr int i=l[pos[x]];i<=r[pos[x]];++i) a[i]+=z*(i>=x),b[i]=a[i];
    for (rr int i=l[pos[y]];i<=r[pos[y]];++i) a[i]+=z*(i<=y),b[i]=a[i];
    sort(b+l[pos[x]],b+1+r[pos[x]]),sort(b+l[pos[y]],b+1+r[pos[y]]);
    for (rr int i=pos[x]+1;i<pos[y];++i) lazy[i]+=z;
}
inline signed ef(int l1,int r1,int w){
    rr int t=r1; ++r1; 
    while (l1<r1){
        rr int mid=(l1+r1)>>1;
        if (b[mid]<w) l1=mid+1;
            else r1=mid;
    }
    return t-l1+1;
}
inline signed query(int x,int y,int z){
    rr int ans=0;
    if (pos[x]==pos[y]){
        for (rr int i=x;i<=y;++i)
            ans+=a[i]+lazy[pos[i]]>=z;
    }
    else{
        for (rr int i=x;i<=r[pos[x]];++i) ans+=a[i]+lazy[pos[i]]>=z;
        for (rr int i=l[pos[y]];i<=y;++i) ans+=a[i]+lazy[pos[i]]>=z;
        for (rr int i=pos[x]+1;i<pos[y];++i) ans+=ef(l[i],r[i],z-lazy[i]);
    }
    return ans;
}
signed main(){
    n=iut(); m=iut(); bk=pow(n,9.0/17); cnt=n/bk+(n%bk>0);
    for (rr int i=1;i<=n;++i) b[i]=a[i]=iut();
    for (rr int i=1;i<=n;++i) pos[i]=(i-1)/bk+1;
    for (rr int i=1;i<=cnt;++i) l[i]=r[i-1]+1,r[i]=i*bk; r[cnt]=n;
    for (rr int i=1;i<=cnt;++i) sort(b+l[i],b+1+r[i]);
    while (m--){
        rr char c=getchar();
        while (!isalpha(c)) c=getchar();
        rr int x=iut(),y=iut(),z=iut();
        if (c=='A') print(query(x,y,z)),putchar(10);
            else update(x,y,z);
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值