#6283. 数列分块入门 7

题目链接:https://loj.ac/problem/6283

题目描述

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

输入格式

第一行输入一个数字 n。

第二行输入 n 个数字,第 i 个数字为 aia_iai,以空格隔开。

接下来输入 n 行询问,每行输入四个数字 opt、lrc,以空格隔开。

若 opt=0,表示将位于 [l,r] 的之间的数字都加 c。

opt=1,表示将位于 [l,r] 的之间的数字都乘 c。

若 opt=2,表示询问 ar 的值 mod 10007(l和 c 忽略)。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

7
1 2 2 3 9 3 2
0 1 3 1
2 1 3 1
1 1 4 4
0 1 7 2
1 2 6 4
1 1 6 5
2 2 6 4

样例输出

3
100

思路:容易知道加法操作会影响乘法操作的值。
但我们可以用sum[]存整块的加数,m[]存整块的乘的系数。容易知道,乘的时候sum也要乘。
比如:
数值x第一个操作加c1,数值变成了x+c1。用sum[]存c1;
第二个操作乘以c2,数值变成(x+c1)*c2,可以理解为c2*x+c1*c2,用sum[]存c1*c2,m[]存c2。

但要注意不完整块的处理,每次不完整的块要更新a[]的值,因为可能前面的操作把它当成完整块处理了,
不完整块要暴力加嘛,所以要变成最新的值才可以暴力加,只有始终为完整块的数可以不用更新.

代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=10007;
ll n,a[maxn],pos[maxn],m[maxn],sum[maxn],block; 

void reset(int x)//更新不完整块中的每个值 
{
    ll p=pos[x];
    for(int i=(p-1)*block+1;i<=min(p*block,n);i++)
        a[i]=(m[p]*a[i]+sum[p])%mod;
    m[p]=1,sum[p]=0;//记得更新该快的sum,m; 
}
void update(int l,int r,int c,int opt)//加和乘 
{
    reset(l);//更新左边不完整块 
    for(int i=l;i<=min(pos[l]*block,(ll)r);i++)//暴力加或乘 
    {
        if(opt==0)
            a[i]=(a[i]+c)%mod;
        else
            a[i]=(a[i]*c)%mod;
    }
    if(pos[l]!=pos[r])
    {
        reset(r);//更新右边不完整块 
        for(int i=(pos[r]-1)*block+1;i<=r;i++)//暴力加或乘 
            if(opt==0)
                a[i]=(a[i]+c)%mod;
            else
                a[i]=(a[i]*c)%mod;
    }
    for(int i=pos[l]+1;i<=pos[r]-1;i++)//完整块处理 
        if(opt==0)
            sum[i]=(sum[i]+c)%mod;//
        else//
        {
            sum[i]=(sum[i]*c)%mod;//sum要乘  关键 
            m[i]=(m[i]*c)%mod;//系数要乘 
        }
}

int main()
{
    scanf("%d",&n);
    block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[i]%=mod;
        pos[i]=(i-1)/block+1;
        m[pos[i]]=1;//系数初始化为1 
    }
    int opt,l,r,c;
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if(opt==0||opt==1)
            update(l,r,c,opt);
        else 
            printf("%lld
",(a[r]*m[pos[r]]+sum[pos[r]])%mod);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xiongtao/p/9799410.html