loj #6278. 数列分块入门 2

题目

题解

区间修改,询问区间小于c的个数。分块排序,用vector。至于那个块的大小,好像要用到均值不等式
我不太会。。。就开始一个个试,发现siz=sqrt(n)/4时最快!!!明天去学一下算分块复杂度的方法。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>

using namespace std;
const int MAXN = 50005;
const int N = 1005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

vector<int> b[N];

int n,siz;
int a[MAXN],l[N],r[N];
int num,bl[MAXN],inc[MAXN];

inline void reset(int id){
    b[id].clear();
    for(register int i=l[id];i<=r[id];i++) b[id].push_back(a[i]);
    sort(b[id].begin(),b[id].end());
}

inline void build(){
    siz=sqrt(n);
    siz/log2(n);
    num=n/siz;
    if(n%siz) num++;
    for(register int i=1;i<=n;i++)
        bl[i]=(i-1)/siz+1;  
    for(register int i=1;i<=num;i++){
        l[i]=(i-1)*siz+1;
        r[i]=i*siz;
    }
    r[num]=n;
    for(register int i=1;i<=num;i++) reset(i);
}

inline void update(int ql,int qr,int w){
    if(bl[ql]==bl[qr]){
        for(register int i=ql;i<=qr;i++)
            a[i]+=w;
        reset(bl[ql]);
        return;
    }
    for(register int i=ql;i<=r[bl[ql]];i++)
        a[i]+=w;
    reset(bl[ql]);
    for(register int i=bl[ql]+1;i<bl[qr];i++)   
        inc[i]+=w;
    for(register int i=l[bl[qr]];i<=qr;i++)
        a[i]+=w;
    reset(bl[qr]);
}

inline int query(int ql,int qr,int c){
    int ret=0;
    if(bl[ql]==bl[qr]){
        for(register int i=ql;i<=qr;i++)
            ret+=(a[i]+inc[bl[i]]<c);
        return ret;
    }
    for(register int i=ql;i<=r[bl[ql]];i++)
        ret+=(a[i]+inc[bl[i]]<c);
    for(register int i=l[bl[qr]];i<=qr;i++)
        ret+=(a[i]+inc[bl[i]]<c);
    for(register int i=bl[ql]+1;i<bl[qr];i++){
        int tar=c-inc[i];
        ret+=lower_bound(b[i].begin(),b[i].end(),tar)-b[i].begin();
    }
    return ret;
}

int main(){
    n=rd();
    for(register int i=1;i<=n;i++) a[i]=rd();
    build();
    for(register int i=1;i<=n;i++){
        int op,L,R,k;
        op=rd();L=rd();R=rd();k=rd();
        if(op==0)
            update(L,R,k);
        else
            printf("%d\n",query(L,R,k*k));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值