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

· · 题解

一个线段树模板题

重点在如何处理乘法,稍不注意就会出现错误

乘法的操作近似于加法,单个剖析出来乘法仅仅是不用知道区间长度
可是两个在一起的时候就要将要加的值乘一遍

记得开long long,原本我以为不像线段树1要开long long,要记得modp

code:

#include <iostream>
#define ll long long
#define pushup(pos) tree[pos]=(tree[pos<<1]+tree[pos<<1|1])%p
using namespace std;
ll tree[100000<<2],add[100000<<2],mul[100000<<2],p;
int n,m;
void pushdown1(int pos){//乘法下推
    mul[pos<<1]=(mul[pos<<1]*mul[pos])%p;mul[pos<<1|1]=(mul[pos<<1|1]*mul[pos])%p;//乘法相乘
    add[pos<<1]=(add[pos<<1]*mul[pos])%p;add[pos<<1|1]=(add[pos<<1|1]*mul[pos])%p;//加法相乘
    tree[pos<<1]=(tree[pos<<1]*mul[pos])%p;tree[pos<<1|1]=(tree[pos<<1|1]*mul[pos])%p;//值相乘
    mul[pos]=1;//清1(这里不是0,不然倍数都变0了)
}
void pushdown2(int ls,int rs,int pos){//加法下推
    add[pos<<1]=(add[pos<<1]+add[pos])%p;add[pos<<1|1]=(add[pos<<1|1]+add[pos])%p;//加法相加
    tree[pos<<1]=(tree[pos<<1]+add[pos]*ls)%p;tree[pos<<1|1]=(tree[pos<<1|1]+add[pos]*rs)%p;//值相加
    add[pos]=0;//加法清0
}
void build(int l,int r,int pos){//建树
    if(l==r) {cin>>tree[pos];tree[pos]%=p;return;}
    int mid=(l+r)>>1;
    build(l,mid,pos<<1);build(mid+1,r,pos<<1|1);
    pushup(pos);
}
void update1(int L,int R,int l,int r,ll k,int pos){//乘法
    if(l>=L&&r<=R) {tree[pos]=(tree[pos]*k)%p;mul[pos]=(mul[pos]*k)%p;add[pos]=(add[pos]*k)%p;return;}
    int mid=(l+r)>>1;
    pushdown1(pos);pushdown2(mid-l+1,r-mid,pos);
    if(L<=mid) update1(L,R,l,mid,k,pos<<1);
    if(R>mid) update1(L,R,mid+1,r,k,pos<<1|1);
    pushup(pos);
}
void update2(int L,int R,int l,int r,ll k,int pos){//加法
    if(l>=L&&r<=R) {tree[pos]=(tree[pos]+k*(r-l+1))%p;add[pos]=(add[pos]+k)%p;return;}
    int mid=(l+r)>>1;
    pushdown1(pos);pushdown2(mid-l+1,r-mid,pos);
    if(L<=mid) update2(L,R,l,mid,k,pos<<1);
    if(R>mid) update2(L,R,mid+1,r,k,pos<<1|1);
    pushup(pos);
}
ll query(int L,int R,int l,int r,int pos){//求和
    if(l>=L&&r<=R) return tree[pos];
    int mid=(l+r)>>1;
    pushdown1(pos);pushdown2(mid-l+1,r-mid,pos);
    return ((mid>=L?query(L,R,l,mid,pos<<1):0)+(R>mid?query(L,R,mid+1,r,pos<<1|1):0))%p;
}
int main(){
    for(register int i=1;i<100000<<2;i++) mul[i]=1;//清1
    cin>>n>>m>>p;
    build(1,n,1);
    while(m--)
    {
        int t,l,r;
        ll k;
        cin>>t>>l>>r;
        if(t==1) {cin>>k;k%=p;update1(l,r,1,n,k,1);}
        else if(t==2) {cin>>k;k%=p;update2(l,r,1,n,k,1);}
        else cout<<query(l,r,1,n,1)<<endl;
    }
    return 0;
}

管理员大大,我觉得这题可以拓展个xx区间相乘的积