题目链接:
题目大意:


很显然,如果只有区间乘法,和分块入门 1 的做法没有本质区别,但要思考如何同时维护两种标记。

我们让乘法标记的优先级高于加法(如果反过来的话,新的加法标记无法处理)

若当前的一个块乘以m1后加上a1,这时进行一个乘m2的操作,则原来的标记变成m1 * m2,a1 * m2

若当前的一个块乘以m1后加上a1,这时进行一个加a2的操作,则原来的标记变成m1,a1+a2

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//由块号寻找第一个块元素的下标
#define LL(x) ((x-1)*Len+1)
const int mod=10007;
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int a[100005], b[100005], add1[1005], add2[1005];
int Len, n;

void reset(int x)//标记下推
{
    for(int i=LL(x);i<min(LL(x+1), n);i++)
    {
        a[i]=(a[i]*add1[x]+add2[x])%mod;
    }
    add1[x]=1, add2[x]=0;
}

void Add(int k, int L, int R, int c)
{
    int bL=b[L], bR=b[R];
    if(bL==bR)
    {
        reset(bL);
        for(int i=L;i<=R;i++)
        {
            if(k==0)
            {
                a[i]=(a[i]+c)%mod;
            }
            else
            {
                a[i]=(a[i]*c)%mod;
            }
        }
    }
    else
    {
        reset(bL);
        for(int i=L;i<LL(bL+1);i++)
        {
            if(k==0)
            {
                a[i]=(a[i]+c)%mod;
            }
            else
            {
                a[i]=(a[i]*c)%mod;
            }
        }

        for(int i=bL+1; i<bR; i++)
        {
            if(k==0)
            {
                add2[i]=(add2[i]+c)%mod;
            }
            else
            {
                add1[i]=(add1[i]*c)%mod;
                add2[i]=(add2[i]*c)%mod;
            }
        }

        reset(bR);
        for(int i=LL(bR);i<=R;i++)
        {
            if(k==0)
            {
                a[i]=(a[i]+c)%mod;
            }
            else
            {
                a[i]=(a[i]*c)%mod;
            }
        }
    }
}

void build(int n)
{
    Len=n/sqrt(n);
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        b[i]=(i-1)/Len+1;
        add1[(i-1)/Len+1]=1;
        add2[(i-1)/Len+1]=0;
    }
}

int main()
{
    n=read();
    build(n);

    for(int i=1;i<=n;i++)
    {
        int op=read(), L=read(), R=read(), c=read();
        if(op==0)//+c
        {
            Add(op, L, R, c);
        }
        if(op==1)//*c
        {
            Add(op, L, R, c);
        }
        if(op==2)//询问
        {
            printf("%d\n",(a[R]*add1[(R-1)/Len+1]+add2[(R-1)/Len+1])%mod);
        }
    }

    return 0;
}