分块#6278. 数列分块入门 2

原题:https://loj.ac/problem/6278
修改自:https://www.cnblogs.com/xiongtao/p/9746789.html

//
//  main.cpp
//  tmpFENKUAI
//
//  Created by RogerQian on 2019/6/5.
//  Copyright © 2019 RogerQian. All rights reserved.
//

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

using namespace std;

const int maxn=50010;
int block,a[maxn],lazy[maxn],pos[maxn];//block块大小,a原数列,pos是a的所属块标记

vector<int>v[555];//存放每个块

int n;

void reset(int x)//对于左右块进行重新排序
{
    v[pos[x]].clear();
    for (int i=(pos[x]-1)*block+1; i<=min(pos[x]*block,n); i++) {
        v[pos[x]].push_back(a[i]);
    }
    sort(v[pos[x]].begin(),v[pos[x]].end());
}

void update(int l, int r, int c)//更新操作
{
    for (int i=l; i<=min(pos[l]*block,r); i++) {
        a[i]+=c;
    }
    reset(l);//left
    
    if(pos[l]!=pos[r])
    {
        for (int i= (pos[r]-1)*block+1; i<=r; i++) {
            a[i]+=c;
        }
        reset(r);
    }//right
    
    for (int i =pos[l]+1; i<=pos[r]-1; i++) {
        lazy[i]+=c;
    }//midle
}



int query(int l, int r, int c)//查询操作
{
    int ans=0;
    
    for (int i=l; i<=min(pos[l]*block,r); i++) {
        if(a[i]+lazy[pos[l]]<c) ans++;
    }//left
    
    if (pos[l]!=pos[r]) {
        for (int i=(pos[r]-1)*block+1; i<=r; i++) {
            if (a[i]+lazy[pos[r]]<c) {
                ans++;
            }
        }
    }//right
    
    for (int i=pos[l]+1; i<=pos[r]-1; i++) {
        int x=c-lazy[i];
        ans+=lower_bound(v[i].begin(),v[i].end(),x)-v[i].begin();//二分查找
    }
    return ans;
}





int main()
{
    //int n;
    scanf("%d",&n);
    block = sqrt(n);
    
    for (int i=1; i<=n; i++) {
        scanf("%d",&a[i]);//录入
        pos[i]=(i-1)/block+1;//标记块组
        v[pos[i]].push_back(a[i]);//压入
    }
    for (int i=1; i<=pos[n]; i++) {
        sort(v[i].begin(),v[i].end());
    }
    
    
    int opt,l,r,c;
    for (int i=1; i<=n; i++) {
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if (opt==0) update(l,r,c);
        else printf("%d\n",query(l,r,c*c));
    }
    
    return 0;
}

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值