Title

P3373 【模板】线段树 2 题解

解题思路

分块做法

加法乘法打上标记,然后零散块下传一下就可以了。

开 long long 后减少取模次数可以有效减少运行时间。

然后加上快读就可以稳定 AC 了。

AC 代码

#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define int long long
#define N 100005
#define M 350
void read(int &x){
    x=0;bool flag(0);char ch=getchar();
    while(ch<'0'||ch>'9') flag^=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    flag?x=-x:0;
}
void write(int x)
{
    x<0?x=-x,putchar('-'):0;static short Stack[50],top(0);
    do Stack[++top]=x%10,x/=10;while(x);
    while(top) putchar(Stack[top--]|48);
    putchar('\n');
}
int n,q,a[N];
int Mod,pos[N];
struct Block{
    int l,r;
    int add;
    int mul;
    int sum;
    int len;
    Block():mul(1){}
    inline void Init(){
        for(register int i=l;i<=r;++i)
            sum+=a[i];
        sum%=Mod;
        len=r-l+1;
    }
    inline void Add(
        const int &v
    ){
        add+=v;
        sum+=v*len;
        sum%=Mod;
    }
    inline void Mul(
        const int &v
    ){
        mul=mul*v%Mod;
        sum=sum*v%Mod;
        add=add*v%Mod;
    }
    inline void Update(){
        for(register int i=l;i<=r;++i){
            if(mul!=1ll)
                a[i]*=mul;
            a[i]%=Mod;
            a[i]+=add;
        }mul=1ll;sum=add=0ll;
        for(register int i=l;i<=r;++i)
            sum+=a[i];
        sum%=Mod;
    }
}block[M];
inline void Add(
    const int &l,
    const int &r,
    const int &v
){
    register int x=pos[l];
    register int y=pos[r];
    if(x==y){
        block[x].Update();
        for(register int i=l;i<=r;++i)
            a[i]+=v;
        block[x].Update();
        return;
    }
    block[x].Update();
    for(register int i=l;i<=block[x].r;++i)
        a[i]+=v;
    block[x].Update();
    block[y].Update();
    for(register int i=block[y].l;i<=r;++i)
        a[i]+=v;
    block[y].Update();
    for(register int i=x+1;i<y;++i)
        block[i].Add(v);
}
inline void Mul(
    const int &l,
    const int &r,
    const int &v
){
    register int x=pos[l];
    register int y=pos[r];
    if(x==y){
        block[x].Update();
        for(register int i=l;i<=r;++i)
            a[i]=a[i]*v;
        block[x].Update();
        return;
    }
    block[x].Update();
    for(register int i=l;i<=block[x].r;++i)
        a[i]=a[i]*v;
    block[x].Update();
    block[y].Update();
    for(register int i=block[y].l;i<=r;++i)
        a[i]=a[i]*v;
    block[y].Update();
    for(register int i=x+1;i<y;++i)
        block[i].Mul(v);
}
inline void Query(
    const int &l,
    const int &r
){
    register int x=pos[l];
    register int y=pos[r];
    if(x==y){
        register int res=0;
        block[x].Update();
        for(register int i=l;i<=r;++i)
            res+=a[i];
        write(res%Mod);
        return;
    }
    register int res=0;
    block[x].Update();
    for(register int i=l;i<=block[x].r;++i)
        res+=a[i];
    block[y].Update();
    for(register int i=block[y].l;i<=r;++i)
        res+=a[i];
    for(register int i=x+1;i<y;++i)
        res+=block[i].sum;
    write(res%Mod);
}
signed main(){
    read(n),read(q);read(Mod);
    for(register int i=1;i<=n;++i)
        read(a[i]);
    int t=sqrt(n+1);
    for(register int i=1;i<=t;++i){
        block[i].r=i*t;
        block[i].l=(i-1)*t+1;
    }
    if(block[t].r<n){
        ++t;block[t].r=n;
        block[t].l=block[t-1].r+1;
    }
    for(register int i=1;i<=t;++i)
    for(
        register int j=block[i].l;
        j<=block[i].r;++j
    ) pos[j]=i;
    for(register int i=1;i<=t;++i)
        block[i].Init();
    int opt,l,r,x;
    while(q--){
        read(opt);
        read(l),read(r);
        if(opt<3) read(x);
        switch (opt){
            case 1:Mul(l,r,x);break;
            case 2:Add(l,r,x);break;
            case 3:Query(l,r);break;
        }
    }
}
posted @   UncleSam_Died  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示