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

· · 题解

//蛤蛤蛤蛤蛤蛤,各种常数优化懒标优化史上最快!!!(众人:不对啊还有指针呢?我:。。。咱打个题解不容易能不能忽略一下细节。。。而且搞了一个多月。。。)

//搞了1个多月,终于搞完了呜呜呜~~~

//要注意乘法分配律,因为在懒惰标记中乘法会影响加法,而加法并不会影响乘法(假装严肃。。。)

//最最重要的一点(我搞了一个多月就是因为它呜呜呜~),无论执行任何操作(建树除外),执行之前一定一定千万千万mustmust把当前节点的懒惰标记下放,因为查询时是从上向下寻找懒惰标记的,如果在每次查询不执行下放操作加法乘法先后次序就出事了(我就是错在这里的。。。呜呜呜~)

附上我V587的代码(蛤蛤蛤蛤蛤蛤)

pra\

gma GCC optimize("O3")//这是传说中的O3优化(小小吐槽一下洛谷,#pragma关键字居然不让用,弄得我还得打个“\",还得打个换行。。。)

#include<stdio.h>
using namespace std;
int n,m;
unsigned long long p,vv[1000020],ll[2000050],rr[2000050],mm[2000050],k,jia[2000050],cheng[2000050];
char ch;
inline void iin(int &kk){
    ch=getchar();
    for(;ch!='-'&&(ch<48||ch>57);){
        ch=getchar();
    }
    if(ch=='-'){
        ch=getchar();
        for(;ch>=48&&ch<=57;){
            kk=(kk<<1)+(kk<<3)+ch-48;
            ch=getchar();
        }
        kk=-kk;
        return;
    }
    for(;ch>=48&&ch<=57;){
        kk=(kk<<1)+(kk<<3)+ch-48;
        ch=getchar();
    }
}
inline void lin(unsigned long long &kk){
    ch=getchar();
    for(;ch!='-'&&(ch<48||ch>57);){
        ch=getchar();
    }
    if(ch=='-'){
        ch=getchar();
        for(;ch>=48&&ch<=57;){
            kk=(kk<<1)+(kk<<3)+ch-48;
            ch=getchar();
        }
        kk=-kk;
        return;
    }
    for(;ch>=48&&ch<=57;){
        kk=(kk<<1)+(kk<<3)+ch-48;
        ch=getchar();
    }
}
unsigned long long build(int l,int r,int id){
    cheng[id]=1;
    if(l==r){
        lin(vv[id]);//建树时的神奇优化,节约空间蛤蛤蛤蛤蛤蛤
        vv[id]%=p;
        ll[id]=rr[id]=mm[id]=l;
        return vv[id];
    }
    ll[id]=l;
    rr[id]=r;
    int mid=(l+r)>>1;
    mm[id]=mid;
    return vv[id]=(build(l,mid,id<<1)+build(mid+1,r,(id<<1)|1))%p;
}
inline void low(int id){
    vv[id]=(cheng[id]*vv[id]%p+jia[id]*(rr[id]-ll[id]+1)%p)%p;
    int lid=id<<1,rid=(id<<1)|1;
    if(cheng[id]!=1){
        cheng[lid]*=cheng[id],cheng[lid]%=p;
        cheng[rid]*=cheng[id],cheng[rid]%=p;
        jia[lid]*=cheng[id],jia[lid]%=p;
        jia[rid]*=cheng[id],jia[rid]%=p;
        cheng[id]=1;
    }
    if(jia[id]){
        jia[lid]+=jia[id],jia[lid]%=p;
        jia[rid]+=jia[id],jia[rid]%=p;
        jia[id]=0;
    }

}//神奇的下放操作 unsigned long long chengg(int l,int r,unsigned long long change,int id){

    low(id);
//    printf("cheng%d %d %d %d\n",l,r,id,mm[id]);
    int mmm=mm[id];
    if(l==ll[id]&&r==rr[id]){
        unsigned long long uu=cheng[id];
        cheng[id]=(cheng[id]*change)%p;
        unsigned long long u=jia[id];
        jia[id]=(jia[id]*change)%p;
        return ((cheng[id]-uu)*vv[id]%p+(jia[id]-u)*(r-l+1)%p)%p;
    }
    if(mmm>=r){
        unsigned long long u=chengg(l,r,change,id<<1)%p;
        u%=p;
        vv[id]=(vv[id]+u)%p;
        return u;
    }
    if(mmm<l){
        unsigned long long u=chengg(l,r,change,(id<<1)|1)%p;
        u%=p;
        vv[id]=(vv[id]+u)%p;
        return u;
    }
    unsigned long long u=(chengg(l,mmm,change,id<<1)+chengg(mmm+1,r,change,(id<<1)|1))%p;
    vv[id]=(vv[id]+u)%p;
    return u;
}
void jiaa(int l,int r,unsigned long long change,int id){
    low(id);
    int lll=ll[id],rrr=rr[id];
    if(l==lll&&r==rrr){
        jia[id]=(jia[id]+change)%p;
        return;
    }
    int mmm=mm[id];
    vv[id]=(vv[id]%p+(r-l+1)*change%p)%p;
//    printf("jia%d %d %d %d ",l,r,id,mm[id]);
//    printf("%lld\n",vv[id]);
    if(mmm>=r){
        jiaa(l,r,change,id<<1);
        return;
    }
    if(mmm<l){
        jiaa(l,r,change,(id<<1)|1);
        return;
    }
    jiaa(l,mmm,change,id<<1);
    jiaa(mmm+1,r,change,(id<<1)|1);
}
unsigned long long out(int l,int r,int id){
//    printf("out%d %d %d\n",l,r,id);
    low(id);
//    printf("a%lld ",cheng[id]);
//    printf("s%lld\n",jia[id]);
//    printf("%d %d %d %d\n",l,r,id,vv[id]);
    if(l==ll[id]&&r==rr[id]){
        return vv[id];
    }
    int mid=mm[id],lid=id<<1,rid=(id<<1)|1;;
    if(mid>=r){
        return out(l,r,lid);
    }
    if(mid<l){
        return out(l,r,rid);
    }
    return (out(l,mid,lid)+out(mid+1,r,rid))%p;
}
int main(){
    iin(n),iin(m),lin(p);
    build(1,n,1);
    int num=0,x=0,y=0;
    for(int i=0;i<m;i++){
        iin(num),iin(x),iin(y);
        if(num>>1){
            if(num&1){
                printf("%llu\n",out(x,y,1)%p);
            }
            else{
                lin(k);
                jiaa(x,y,k%p,1);
                k=0;
            }
        }
        else{
            lin(k);
            chengg(x,y,k%p,1);
            k=0;
        }
        num=x=y=0;
    }
    for(int i=1;i<=9;i++){
//        printf("%lld ",vv[i]*cheng[i]+jia[i]*(rr[i]-ll[i]+1));
    }
    return 0;
}