【滚动训练】LOJ6283. 数列分块入门 7 (分块)

题意

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

题解

主要考虑如何维护加法和乘法标记。
考虑一般情况,设任意块内中任意元素为 x x ,所携带的加法标记为a,所携带的乘法标记为 m m

  1. 现在对区间进行加法,加数为a,原先的值为 mx+a m x + a ,进行加法后的值为 mx+a+a m x + a + a ′ ,所以只需要更新加法标记,变为 a+a a + a ′

    • 现在对区间进行乘法,乘数为 m m ′ ,原先的值为 mx+a m x + a ,进行乘法后的值为 mmx+am m ′ m x + a m ′ ,所以需要更新加法和乘法标记,乘法标记变为 mm m ∗ m ′ ,加法标记变为 am a ∗ m ′
    • 对于左右边界块内的部分,首先把所有标记下放,然后暴力更新数据值。
    • 代码

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      typedef unsigned long long ull;
      const int nmax = 100000+100;
      const int INF = 0x3f3f3f3f;
      const ll MOD = 10007;
      const int mm = sqrt(1e5+100)+10;
      ll data[nmax],add[mm],mul[mm];
      int L[mm],R[mm],belong[nmax],block,num,n;
      inline void init(){
          block = sqrt(n);
          num = n / block; if(n % block) num++;
          for(int i = 1;i<=num;++i){L[i] = (i-1)* block + 1; R[i] = i * block; mul[i] = 1;}
          R[num] = n;
      }
      inline void pushdown(int cur){
          if(mul[cur] == 1 && add[cur] == 0) return;
          for(int i = L[cur];i<=R[cur];++i) data[i] = ((data[i] * mul[cur])%MOD + add[cur]) % MOD;
          mul[cur] = 1, add[cur] = 0;
      }
      int main(){
          scanf("%d",&n); init();
          for(int i = 1;i<=n;++i){ scanf("%lld",&data[i]); belong[i] = (i-1) / block + 1; }
          int op,l,r; ll w;
          for(int j = 1;j<=n;++j){
              scanf("%d %d %d %lld",&op,&l,&r,&w);
              if(op == 0){
                  pushdown(belong[l]);
                  for(int i = l;i<=min(r,R[belong[l]]);++i) data[i] = (data[i] + w) % MOD;
                  if(belong[r] != belong[l]){ pushdown(belong[r]); for(int i = L[belong[r]];i<=r;++i) data[i] = (data[i] + w) % MOD;}
                  for(int i = belong[l]+1;i<=belong[r]-1;++i) add[i] = (add[i]+w)%MOD;
              }else if(op == 1){
                  pushdown(belong[l]);
                  for(int i = l;i<=min(r,R[belong[l]]);++i) data[i] = (data[i] * w)% MOD;
                  if(belong[r] != belong[l]) {pushdown(belong[r]); for(int i = L[belong[r]];i<=r;++i) data[i] = (data[i]*w) % MOD;}
                  for(int i = belong[l]+1;i<=belong[r]-1;++i) mul[i] = (mul[i] *w) %MOD, add[i] = (add[i]*w)%MOD;
              }else{
                  ll ans = ((data[r] * mul[belong[r]]) % MOD + add[belong[r]] ) % MOD;
                  printf("%lld\n",ans);
              }
          }
          return 0;
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值