loj#6283. 数列分块入门 7

#6283. 数列分块入门 7

题目:传送门 

简要题意:

   给出一个长为 n 的数列,以及 n 个操作,操作涉及区间乘法,区间加法,单点询问。

 


 

 

题解:

   类似于bzoj的序列维护seq,很想打个线段树...

   用分块其实和线段数的操作也是一样的,也就是加两个lazy标记...

   要注意的是每次修改的时候,要先将身上的lazy更新到原数列...

   码码码码...

 


 

 

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define mod 10007
#define qread(x) x=read()
using namespace std;
typedef long long LL;
inline LL read()
{
    LL x=0,f=1;char ch;
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
LL n,a[110000],lzj[110000],lzc[110000];
LL block,pos[110000];
void add(LL l,LL r,LL c)
{
    if(pos[l]==pos[r])
    {
        for(int i=(pos[l]-1)*block+1;i<=pos[l]*block;i++)a[i]=(a[i]*lzc[pos[l]]+lzj[pos[l]])%mod;
        lzc[pos[l]]=1;lzj[pos[l]]=0;
        for(int i=l;i<=r;i++)a[i]=(a[i]+c)%mod;
    }
    else
    {
        for(int i=pos[l]+1;i<=pos[r]-1;i++)lzj[i]=(lzj[i]+c)%mod;
        
        for(int i=(pos[l]-1)*block+1;i<=pos[l]*block;i++)a[i]=(a[i]*lzc[pos[l]]+lzj[pos[l]])%mod;
        lzj[pos[l]]=0;lzc[pos[l]]=1;
        for(int i=l;i<=pos[l]*block;i++)a[i]=(a[i]+c)%mod;
        
        for(int i=(pos[r]-1)*block+1;i<=pos[r]*block;i++)a[i]=(a[i]*lzc[pos[r]]+lzj[pos[r]])%mod;
        lzj[pos[r]]=0;lzc[pos[r]]=1;
        for(int i=(pos[r]-1)*block+1;i<=r;i++)a[i]=(a[i]+c)%mod;
    }
}
void multi(LL l,LL r,LL c)
{
    if(pos[l]==pos[r])
    {
        for(int i=(pos[l]-1)*block+1;i<=pos[l]*block;i++)a[i]=(a[i]*lzc[pos[l]]+lzj[pos[l]])%mod;
        lzc[pos[l]]=1;lzj[pos[l]]=0;
        for(int i=l;i<=r;i++)a[i]=(a[i]*c)%mod;
    }
    else
    {
        for(int i=pos[l]+1;i<=pos[r]-1;i++)lzc[i]=(lzc[i]*c)%mod,lzj[i]=(lzj[i]*c)%mod;
        
        for(int i=(pos[l]-1)*block+1;i<=pos[l]*block;i++)a[i]=(a[i]*lzc[pos[l]]+lzj[pos[l]])%mod;
        lzj[pos[l]]=0;lzc[pos[l]]=1;
        for(int i=l;i<=pos[l]*block;i++)a[i]=(a[i]*c)%mod;
        
        for(int i=(pos[r]-1)*block+1;i<=pos[r]*block;i++)a[i]=(a[i]*lzc[pos[r]]+lzj[pos[r]])%mod;
        lzj[pos[r]]=0;lzc[pos[r]]=1;
        for(int i=(pos[r]-1)*block+1;i<=r;i++)a[i]=(a[i]*c)%mod;
    }
}
int main()
{
    qread(n);for(int i=1;i<=n;i++)qread(a[i]);
    for(int i=1;i<=n;i++)lzc[i]=1;
    block=sqrt(n);for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
    for(int i=1;i<=n;i++)
    {
        LL opt,l,r,c;qread(opt);qread(l);qread(r);qread(c);
        if(opt==0)add(l,r,c);
        else if(opt==1)multi(l,r,c);
        else printf("%lld\n",(a[r]*lzc[pos[r]]+lzj[pos[r]])%mod);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/CHerish_OI/p/8580709.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值