#6278. 数列分块入门 2

题目链接:https://loj.ac/problem/6278

题目描述

给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,询问区间内小于某个值 xx 的元素个数。

输入格式

第一行输入一个数字 nn。

第二行输入 nn 个数字,第 ii 个数字为 a_iai,以空格隔开。

接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。

若 \mathrm{opt} = 0opt=0,表示将位于 [l, r][l,r] 的之间的数字都加 cc。

若 \mathrm{opt} = 1opt=1,表示询问 [l, r][l,r] 中,小于 c^2c2 的数字的个数。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2

样例输出

3
0
2

数据范围与提示

对于 100\%100% 的数据,1 \leq n \leq 50000, -2^{31} \leq \mathrm{others}1n50000,231others、\mathrm{ans} \leq 2^{31}-1ans2311。

个人思路:二分查找区间里面的有多少个符合情况的,时间复杂度差不多是n√nlog√n

#include<iostream>
#include<math.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=50000+5;
int a[maxn];
int bl[maxn];
int atag[maxn];//存储每个块中所有的元素都要进行的操作
int n;
int block;//块的大小
vector<int>v[maxn];//存储每个块里面的元素
void reset(int x)
{
    v[x].clear();
    for(int i=(x-1)*block+1;i<=x*block;i++) v[x].push_back(a[i]);
    sort(v[x].begin(),v[x].end());
}
void add(int l,int r,int c)
{
    for(int i=l;i<=min(r,bl[l]*block);i++)//最左边的块
        a[i]+=c;
    reset(bl[l]);//a[i]的值改变了  容器里面也要改变
    if(bl[l]!=bl[r])//等于的话岂不是算的重复了
    {
        for(int i=(bl[r]-1)*block+1;i<=r;i++)//最右边的块
            a[i]+=c;
            reset(bl[r]);
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)//中间的块
        atag[i]+=c;

}
void query(int l,int r,int c)
{
    int ans=0;
    for(int i=l;i<=min(bl[l]*block,r);i++)
    {
        if(a[i]+atag[bl[i]]<c) ans++;
    }
    if(bl[l]!=bl[r])
    {
        for(int i=(bl[r]-1)*block+1;i<=r;i++)
        {
            if(a[i]+atag[bl[i]]<c) ans++;
        }
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    {
        int x=lower_bound(v[i].begin(),v[i].end(),c-atag[i])-v[i].begin();//二分查找有多少个小于c*c的
        ans+=x;
    }
    cout<<ans<<endl;

}
int main()
{
    int opt,l,r,c;
    memset(atag,0,sizeof(atag));
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];//注意下标从1开始 这样更好分块
    block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        bl[i]=(i-1)/block+1;//a[i]属于哪个块
        v[bl[i]].push_back(a[i]);
    }
    for(int i=1;i<=bl[n];i++) sort(v[i].begin(),v[i].end());
    for(int i=1;i<=n;i++)
    {
        cin>>opt>>l>>r>>c;
        if(opt==0) add(l,r,c);
        else query(l,r,c*c);
    }
}

 

 

posted @ 2019-01-23 16:56  执||念  阅读(640)  评论(0编辑  收藏  举报