【洛谷P2023】维护序列

这个板子不打就是手生……一段时间不会处理线段树了qwq,这个题难点就是在于下放标记

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lo;
lo n,p,m,a[100010],x,y,z,fl,qwq;
struct in
{
    lo l,r,s,f1,f2;
}ter[400040];
inline void re(lo &c)
{
    c=0;
    char b=getchar();
    while(b<'0'||b>'9')
        b=getchar();
    while(b>='0'&&b<='9')
        c=c*10+b-'0',b=getchar();
}
inline void u(lo w)
{
    ter[w].s=((ter[w<<1].s%p)+(ter[w<<1|1].s%p))%p;
}
inline void build(lo l,lo r,lo w)
{
    ter[w]=(in){l,r,0,1,0};
    if(l==r)
    {
        ter[w].s=a[l];return;
    }
    lo mid=l+r>>1;
    build(l,mid,w<<1),build(mid+1,r,w<<1|1);
    u(w);
}
inline void d(lo w)
{
    lo f1=ter[w].f1,f2=ter[w].f2;
    if(f1==1&&f2==0)
        return;
    ter[w<<1].f1*=f1,ter[w<<1].f1%=p;//不管加法还是乘法的flag都要乘上他们父亲的乘法flag 
    ter[w<<1|1].f1*=f1,ter[w<<1|1].f1%=p;
    ter[w<<1].f2*=f1,ter[w<<1].f2%=p;
    ter[w<<1|1].f2*=f1,ter[w<<1|1].f2%=p;
    ter[w<<1].f2+=f2,ter[w<<1].f2%=p;//加法还要加上 
    ter[w<<1|1].f2+=f2,ter[w<<1|1].f2%=p;
    ter[w<<1].s*=f1,ter[w<<1].s%=p;//先乘再加 
    ter[w<<1|1].s*=f1,ter[w<<1|1].s%=p;
    ter[w<<1].s+=f2*(ter[w<<1].r-ter[w<<1].l+1),ter[w<<1].s%=p;
    ter[w<<1|1].s+=f2*(ter[w<<1|1].r-ter[w<<1|1].l+1),ter[w<<1|1].s%=p;
    ter[w].f1=1,ter[w].f2=0;//乘法的flag赋为1是因为最起码*1,不能*0 
}
void cha1(lo l,lo r,lo jia,lo w)
{
    if(ter[w].l==l&&ter[w].r==r)//乘法是一起乘 
    {
        ter[w].f1*=jia,ter[w].f1%=p;
        ter[w].f2*=jia,ter[w].f2%=p;
        ter[w].s*=jia,ter[w].s%=p;
        return;
    }
    d(w);
    lo mid=ter[w].l+ter[w].r>>1;
    if(r<=mid)
        cha1(l,r,jia,w<<1);
    else if(l>mid)
        cha1(l,r,jia,w<<1|1);
    else
        cha1(l,mid,jia,w<<1),cha1(mid+1,r,jia,w<<1|1);
    u(w);
}
void cha2(lo l,lo r,lo jia,lo w)
{
    if(ter[w].l==l&&ter[w].r==r)//加法是单独加在加法的flag上 
    {
        ter[w].f2+=jia,ter[w].f2%=p;
        ter[w].s+=jia*(ter[w].r-ter[w].l+1),ter[w].s%=p;
        return;
    }
    d(w);
    lo mid=ter[w].l+ter[w].r>>1;
    if(r<=mid)
        cha2(l,r,jia,w<<1);
    else if(l>mid)
        cha2(l,r,jia,w<<1|1);
    else
        cha2(l,mid,jia,w<<1),cha2(mid+1,r,jia,w<<1|1);
    u(w);
}
lo ask(lo l,lo r,lo w)
{
    if(ter[w].l==l&&ter[w].r==r)
        return ter[w].s;
    lo mid=ter[w].l+ter[w].r>>1,re=0;
    d(w);
    if(r<=mid)
        re+=ask(l,r,w<<1)%p;
    else if(l>mid)
        re+=ask(l,r,w<<1|1)%p;
    else
        re+=ask(l,mid,w<<1)%p,re+=ask(mid+1,r,w<<1|1)%p;
    u(w);
    return re;
}
int main()
{
    re(n),re(p);
    for(int i=1;i<=n;i++)
        re(a[i]);
    build(1,n,1);//建树 
    re(m);
    for(int i=1;i<=m;i++)
    {
        re(fl),re(x),re(y);
        if(fl==1)
            re(z),cha1(x,y,z,1);//区间乘 
        if(fl==2)
            re(z),cha2(x,y,z,1);//区间加 
        if(fl==3)
            qwq=ask(x,y,1)%p,printf("%lld\n",qwq);//查询 
    }
}

 

posted @ 2017-11-08 21:42  那一抹落日的橙  阅读(352)  评论(0编辑  收藏  举报