• 分块算法初步


    题意:

    1.给出一个长为  的数列,以及  个操作,操作涉及区间加法,单点查值。

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

    3.给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,询问区间内小于某个值 xx 的前驱(比其小的最大元素)。

    4.给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,区间求和,mod(c+1)。

    原题地址:

    https://loj.ac/problem/6277

    https://loj.ac/problem/6278

    https://loj.ac/problem/6279

    https://loj.ac/problem/6280

    参考博客:https://www.cnblogs.com/Parsnip/p/10458689.html#

    代码:

    #include<bits/stdc++.h>
    
    #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define repp(i,a,b) for(int i=a;i<b;i++)
    #define per(i,a,b) for(int i=a;i>=b;i--)
    #define perr(i,a,b) for(int i=a;i>b;i--)
    #define pb push_back
    #define eb push_back
    #define mst(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    typedef long long ll;
    
    template <typename _Tp> inline _Tp read(_Tp&x){
        char c11=getchar(),ob=0;x=0;
        while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
        while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
    }
    
    
    const int N=1000010,sqrtN=1000;
    int n,t,L[sqrtN],R[sqrtN],pos[N];//L[j]、R[j]分别表示第j个块所管辖区间的左边界和右边界,pos[i]表示序列中第i个元素属于哪个块
    ll a[N],changed[sqrtN],sum[sqrtN];//a数组用来存序列元素,changed数组用来表示每个块中每个元素共同的变化量,sum数组用来存每个块中元素的和
    vector<int>section[N];//用于管理每个块中的元素
    //输入元素
    inline void input()
    {
        scanf("%d",&n);
        rep(i,1,n)scanf("%d",&a[i]);
    }
    //将对应元素存入对应的块
    inline void reset(int x)
    {
        section[x].clear();
        rep(i,L[x],R[x])section[x].pb(a[i]);
        sort(section[x].begin(),section[x].end());
    }
    //预处理,分为sqrt(n)或sqrt(n)+1个块
    inline void init()
    {
        t=sqrt(n);
        rep(i,1,t)
        {
            L[i]=(i-1)*t+1;
            R[i]=i*t;
        }
        if(R[t]<n)t++,L[t]=R[t-1]+1,R[t]=n;
        rep(i,1,t)
        rep(j,L[i],R[i])
        pos[j]=i,sum[i]+=a[j];
        rep(i,1,t)reset(i);
    }
    //区间修改,这里是整体加data
    inline void change(int l,int r,ll data)
    {
        int p=pos[l],q=pos[r];
        if(q==p)
        {
            rep(i,l,r)a[i]+=data;
            sum[p]+=(r-l+1)*data;
            reset(p);
        }
        else
        {
            rep(i,p+1,q-1)changed[i]+=data;
            rep(i,l,R[p])a[i]+=data;
            sum[p]+=(R[p]-l+1)*data;
            reset(p);
            rep(i,L[q],r)a[i]+=data;
            sum[q]+=(r-L[q]+1)*data;
            reset(q);
        }
    }
    //用于更新区间内小于某个值 x 的前驱
    inline void updata(ll &ans2,ll val,ll limit)
    {
        if(val<limit&&val>ans2)ans2=val;
    }
    //查询a[x]的值
    inline ll ask1(int x)
    {
        return a[x]+changed[pos[x]];
    }
    //查询区间内小于某个值limit的元素个数
    inline int ask2(int l,int r,ll limit)
    {
        int p=pos[l],q=pos[r],ans1=0;
        if(p==q)
        {
            rep(i,l,r)
            if(a[i]+changed[p]<limit)ans1++;
        }
        else
        {
            rep(i,p+1,q-1)ans1+=lower_bound(section[i].begin(),section[i].end(),limit-changed[i])-section[i].begin();
            rep(i,l,R[p])if(a[i]+changed[p]<limit)ans1++;
            rep(i,L[q],r)if(a[i]+changed[q]<limit)ans1++;
        }
        return ans1;
    }
    //询问区间内小于某个值 x 的前驱(比其小的最大元素)
    inline ll ask3(int l,int r,ll limit)
    {
        int p=pos[l],q=pos[r];
        ll ans2=-1;
        if(p==q)
        {
            rep(i,l,r)
            updata(ans2,a[i]+changed[p],limit);
        }
        else
        {
            rep(i,p+1,q-1)
            updata(ans2,section[i][lower_bound(section[i].begin(),section[i].end(),limit-changed[i])-section[i].begin()-1]+changed[i],limit);
            rep(i,l,R[p])
            updata(ans2,a[i]+changed[pos[i]],limit);
            rep(i,L[q],r)
            updata(ans2,a[i]+changed[pos[i]],limit);
        }
        return ans2;
    }
    //区间求和取模
    inline ll ask4(int l,int r,ll MOD)
    {
        int p=pos[l],q=pos[r];
        ll ans3=0;
        if(p==q)
        {
            rep(i,l,r)ans3=(ans3+a[i])%MOD;
            ans3=(ans3+(r-l+1)*changed[p])%MOD;
        }
        else
        {
            rep(i,p+1,q-1)ans3=(ans3+sum[i]%MOD+(R[i]-L[i]+1)*changed[i])%MOD;
            rep(i,l,R[p])ans3=(ans3+a[i]+changed[pos[i]])%MOD;
            rep(i,L[q],r)ans3=(ans3+a[i]+changed[pos[i]])%MOD;
        }
        return ans3;
    }
    inline void solve()
    {
        input();
        init();
        int opt,l,r;ll c;
        rep(i,1,n)
        {
            scanf("%d%d%d%lld",&opt,&l,&r,&c);
            if(opt)printf("%lld
    ",ask4(l,r,c+1));
            else change(l,r,c);
        }
    }
    int main()
    {
        solve();
        return 0;
    }
  • 相关阅读:
    阿里笔试题
    springboot-security-jwt
    java 面试架构篇
    java 面试题 mybatis 篇
    Java 多线程并发工具类
    java 面试题 高阶版
    给你的右键菜单添加“VScode”
    HTML重点知识点汇总
    HTML5知识点小结
    给博客园添加百度统计方法
  • 原文地址:https://www.cnblogs.com/chuliyou/p/13492819.html
Copyright © 2020-2023  润新知