• #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);
        }
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    Eclipse
    Android View Attributes
    Android Virtual Device
    Bootstrap
    Nginx常用命令
    [多线程]多线程(Thread、Runnable、Callable)
    Redis、MongoDB及Memcached的区别
    Linux将某目录授权给某组里的某用户
    CentOS修改locale解决调用API乱码问题
    MyBatis与Hibernate的区别?
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10310027.html
Copyright © 2020-2023  润新知