题解 P3373 【【模板】线段树 2】

· · 题解

考虑对于x,如果先乘k1再加k2,k2对k1无影响。如果先加k1,再乘k2,(x+k1)*k2等价于(x*k2)+(k1*k2),所以第二步的乘会对第一步的加产生影响。为了模拟出这个影响,我们在区间乘的时候应该把区间加的lazy数组也乘上相应的数。

(代码中付了调试代码便于理解lazy)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define ll long long
using namespace std;
const ll maxn = 1e6;
ll n,m,p;
ll tree[maxn*4],lazy1[maxn],lazy2[maxn];
inline ll read();
void pushdown1(ll,ll,ll);
void pushdown2(ll,ll,ll);
void build(ll node,ll l,ll r)
{
    if(l == r) {
        tree[node] = read();
        return;
    }
    ll mid = (l + r) >> 1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    tree[node] = (tree[node<<1] + tree[node<<1|1])%p; 
}
void pushdown1(ll node,ll l,ll r)
{
    if(lazy1[node] == 1) return;
    ll mid = (l + r) >> 1;
    lazy1[node<<1] = (lazy1[node<<1]*lazy1[node])%p;
    lazy1[node<<1|1] = (lazy1[node<<1|1]*lazy1[node])%p;
    lazy2[node<<1] = (lazy2[node<<1]*lazy1[node])%p;
    lazy2[node<<1|1] = (lazy2[node<<1|1]*lazy1[node])%p;
    tree[node<<1] = (tree[node<<1]*lazy1[node])%p;
    tree[node<<1|1] = (tree[node<<1|1]*lazy1[node])%p;
    lazy1[node] = 1;//一定要重置 
}
void pushdown2(ll node,ll l,ll r)
{
    if(lazy2[node] == 0) return;
    ll mid = (l + r) >> 1;
    lazy2[node<<1] = (lazy2[node<<1] + lazy2[node])%p;
    lazy2[node<<1|1] = (lazy2[node<<1|1] + lazy2[node])%p;
    tree[node<<1] = (tree[node<<1] + (mid - l + 1)*lazy2[node]%p)%p;
    tree[node<<1|1] = (tree[node<<1|1] + (r - mid)*lazy2[node]%p)%p;
    lazy2[node] = 0;//一定要重置 
}
void update1(ll node,ll l,ll r,ll x,ll y,ll k)
{
    if(x > r || l > y) return;
    if(x <= l && r <= y) {
        pushdown1(node,l,r);
        pushdown2(node,l,r);
        lazy1[node] = (lazy1[node]*k)%p;
        tree[node] = (tree[node]*k)%p;
        return;
    }
    pushdown1(node,l,r);
    pushdown2(node,l,r);
    ll mid = (l + r) >> 1;
    update1(node<<1,l,mid,x,y,k);
    update1(node<<1|1,mid+1,r,x,y,k);
    tree[node] = (tree[node<<1] + tree[node<<1|1])%p;
}
void update2(ll node,ll l,ll r,ll x,ll y,ll k)
{
    if(x > r || l > y) return;
    if(x <= l && r <= y) {
        pushdown1(node,l,r);
        pushdown2(node,l,r);
        lazy2[node] = (lazy2[node] + k)%p;
        tree[node] = (tree[node] + (r - l + 1)*k%p)%p;
        return;
    }
    pushdown1(node,l,r);
    pushdown2(node,l,r);
    ll mid = (l + r) >> 1;
    update2(node<<1,l,mid,x,y,k);
    update2(node<<1|1,mid+1,r,x,y,k);
    tree[node] = (tree[node<<1] + tree[node<<1|1])%p;
}
ll Query(ll node,ll l,ll r,ll x,ll y)
{
    if(x > r || l > y) return 0;
    if(x <= l && r <= y) return tree[node];
    ll mid = (l + r) >> 1;
    pushdown1(node,l,r);
    pushdown2(node,l,r);
    return (Query(node<<1,l,mid,x,y) + Query(node<<1|1,mid+1,r,x,y))%p;
}
int main()
{
    n = read();m = read();p = read();
    for(ll i=0;i<maxn;i++) lazy1[i] = 1;
    build(1,1,n);
//    cout<<" "<<tree[8]<<" "<<tree[9]<<" "<<tree[5]<<" "<<tree[6]<<" "<<tree[7]<<endl;
    ll p,x,y,k;
    while(m-- && scanf("%lld",&p)) {
        if(p == 1) {
            x = read();y = read();k = read();
            update1(1,1,n,x,y,k);
/*    cout<<"lazy1:"<<" ";
    for(int i=1;i<=9;i++) cout<<lazy1[i]<<" ";
    cout<<endl;
    cout<<"lazy2:"<<" ";
    for(int i=1;i<=9;i++) cout<<lazy2[i]<<" ";
    cout<<endl;
    cout<<"tree:"<<" "<<tree[8]<<" "<<tree[9]<<" "<<tree[5]<<" "<<tree[6]<<" "<<tree[7]<<endl;*/
        }
        else if(p == 2) {
            x = read();y = read();k = read();
            update2(1,1,n,x,y,k);
/*    cout<<"lazy1:"<<" ";
    for(int i=1;i<=9;i++) cout<<lazy1[i]<<" ";
    cout<<endl;
    cout<<"lazy2:"<<" ";
    for(int i=1;i<=9;i++) cout<<lazy2[i]<<" ";
    cout<<endl;
    cout<<"tree:"<<" "<<tree[8]<<" "<<tree[9]<<" "<<tree[5]<<" "<<tree[6]<<" "<<tree[7]<<endl;*/
        }
        else {
            x = read();y = read();
            printf("%lld\n",Query(1,1,n,x,y));
/*    cout<<"lazy1:"<<" ";
    for(int i=1;i<=9;i++) cout<<lazy1[i]<<" ";
    cout<<endl;
    cout<<"lazy2:"<<" ";
    for(int i=1;i<=9;i++) cout<<lazy2[i]<<" ";
    cout<<endl;
    cout<<"tree:"<<" "<<tree[8]<<" "<<tree[9]<<" "<<tree[5]<<" "<<tree[6]<<" "<<tree[7]<<endl;*/
        }
    }
    return 0;
}
inline ll read()
{
    ll w=1,x=0;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(ch <= '9' && ch >= '0') {
        x = (x<<1) + (x<<3) + ch - '0';
        ch = getchar();
    }
    return x*w;
}