数列分块入门4 LibreOj 6280

题意

        给出n个数的数列,有n个操作,操作涉及到区间加法区间求和,对(c+1)进行取模

思路

        区间加法依旧是用lazy数组,区间求和我首先想到的是前缀和,对于每一块我们用前缀和,但是我们对于不完整块都是用暴力解决的,所以我还是放弃了前缀和的方法,设置了一个b数组来统计块的和,如果对于完整的块我们直接加上b[i]lazy[i]*block(block是块的长度),这样的话就可以完成区间求和的操作,好吧,这是线段树可以轻而易举的做到,但这里写的是分块。

代码

#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N = 100007;
int l[N],r[N],block,num,belong[N],n,x,y;
ll a[N],lazy[N],b[N];
inline void build()
{
    block=sqrt(n);
    num=n/block;if (n%num) num++;
    for (int i=1;i<=num;i++)
        l[i]=(i-1)*block+1,r[i]=i*block;
    r[num]=n;
 
    for (int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;

    for (int i=1;i<=num;i++)
        for (int j=l[i];j<=r[i];j++)
            b[i]+=a[j];
    //b[i]保存的是第i块的和
}
inline void update(int x,int y,int c)
{
    if (belong[x]==belong[y])
    {
        for (int i=x;i<=y;i++) 
                a[i]+=c,b[belong[x]]+=c;
        return;
    }

    for (int i=x;i<=r[belong[x]];i++)
        a[i]+=c,b[belong[x]]+=c;

    for (int i=belong[x]+1;i<belong[y];i++) lazy[i]+=c;
    //这里b[i]不需要更新是因为加的数都到lazy数组里面去了

    for (int i=l[belong[y]];i<=y;i++)
        a[i]+=c,b[belong[y]]+=c;
    //a[i]进行更新的时候,b[i]也要更新
}
inline ll ask(int x,int y,ll c)
{
    int cnt=0;
    ll ans=0,M=c+1;
    if (belong[x]==belong[y])
    {
        for (int i=x;i<=y;i++)
            ans=(a[i]+ans+lazy[belong[x]])%M;
        return ans;
    }
    for (int i=x;i<=r[belong[x]];i++) 
        ans=(a[i]+ans+lazy[belong[x]])%M;
    for (int i=l[belong[y]];i<=y;i++)
        ans=(a[i]+ans+lazy[belong[y]])%M;
    //对于不完整块我们暴力
    for (int i=belong[x]+1;i<belong[y];i++)
    {
       ans=(ans+b[i]+lazy[i]*block)%M;
       //ans的操作,每次加上b[i](区间和)和lazy[i]*block
    }

    return ans;
}
signed main() 
{
    #ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
    IOS
    int m;
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    build();
    for (int k=1;k<=n;k++)
    {
        int l,r,op;
        ll c;
        cin>>op>>l>>r>>c;
        if (op==0)
            update(l,r,c);
        else 
            cout<<ask(l,r,c)<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值