• 线段树(二)


    题目描述

    如题,已知一个数列,你需要进行下面三种操作:

    • 将某区间每一个数乘上 xx

    • 将某区间每一个数加上 xx

    • 求出某区间每一个数的和

    输入格式

    第一行包含三个整数 n,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。

    第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

    接下来 mm 行每行包含若干个整数,表示一个操作,具体如下:

    操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数乘上 kk

    操作 22: 格式:2 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk

    操作 33: 格式:3 x y 含义:输出区间 [x,y][x,y] 内每个数的和对 pp 取模所得的结果

    输出格式

    输出包含若干行整数,即为所有操作 33 的结果。

    输入输出样例

    in:

    5 5 38
    1 5 4 2 3
    2 1 4 1
    3 2 5
    1 2 4 2
    2 3 5 5
    3 1 4

    out:

    17

    2

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    int n,m,a[1000005],mod;
    struct node
    {
        ll sum,l,r,mu,add;
    } t[1000005];
    ll read()
    {
        ll x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x;
    }
    void build(ll p,ll l,ll r)
    {
        t[p].l=l,t[p].r=r;
        t[p].mu=1;
        if(l==r)
        {
            t[p].sum=a[l]%mod;
            return ;
        }
        ll mid=(l+r)>>1;
        build(p*2,l,mid);
        build(p*2+1,mid+1,r);
        t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
    }
    void spread(ll p)
    {
        t[p*2].sum=(ll)(t[p].mu*t[p*2].sum+((t[p*2].r-t[p*2].l+1)*t[p].add)%mod)%mod;
        t[p*2+1].sum=(ll)(t[p].mu*t[p*2+1].sum+(t[p].add*(t[p*2+1].r-t[p*2+1].l+1))%mod)%mod;//add已经乘过mu啦
    
        t[p*2].mu=(ll)(t[p*2].mu*t[p].mu)%mod;
        t[p*2+1].mu=(ll)(t[p*2+1].mu*t[p].mu)%mod;
    
        t[p*2].add=(ll)(t[p*2].add*t[p].mu+t[p].add)%mod;
        t[p*2+1].add=(ll)(t[p*2+1].add*t[p].mu+t[p].add)%mod;
    
        t[p].mu=1,t[p].add=0;
    }
    void add(ll p,ll l,ll r,ll k)
    {
        if(t[p].l>=l&&t[p].r<=r)
        {
            t[p].add=(t[p].add+k)%mod;
            t[p].sum=(ll)(t[p].sum+k*(t[p].r-t[p].l+1))%mod;//只要加上增加的就好
            return ;
        }
        spread(p);
        t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
        ll mid=(t[p].l+t[p].r)>>1;
        if(l<=mid)add(p*2,l,r,k);
        if(mid<r)add(p*2+1,l,r,k);
        t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
    
    }
    void mu(ll p,ll l,ll r,ll k)
    {
        if(t[p].l>=l&&t[p].r<=r)
        {
            t[p].add=(t[p].add*k)%mod;//比较重要的一步,add要在这里乘上k,因为后面可能要加其他的数而那些数其实是不用乘k的
            t[p].mu=(t[p].mu*k)%mod;
            t[p].sum=(t[p].sum*k)%mod;
            return ;
        }
        spread(p);
        t[p].sum=t[p*2].sum+t[p*2+1].sum;
        ll mid=(t[p].l+t[p].r)>>1;
        if(l<=mid)mu(p*2,l,r,k);
        if(mid<r)mu(p*2+1,l,r,k);
        t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
    }
    ll ask(ll p,ll l,ll r)
    {
        if(t[p].l>=l&&t[p].r<=r)
        {
            return t[p].sum;
        }
        spread(p);
        ll val=0;
        ll mid=(t[p].l+t[p].r)>>1;
        if(l<=mid)val=(val+ask(p*2,l,r))%mod;
        if(mid<r)val=(val+ask(p*2+1,l,r))%mod;
        return val;
    }
    int main()
    {
        cin>>n>>m>>mod;
        for(int i=1; i<=n; i++)
        {
            a[i]=read();
        }
        build(1,1,n);
        for(int i=1; i<=m; i++)
        {
            int ty=read();
            if(ty==1)
            {
                ll cn=read(),cm=read(),cw=read();
                mu(1,cn,cm,cw);
            }
            else if(ty==2)
            {
                ll cn=read(),cm=read(),cw=read();
                add(1,cn,cm,cw);
            }
            else
            {
                ll cn=read(),cm=read();
                cout<<ask(1,cn,cm)<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    java第四次作业
    java第五次作业
    java第三次作业
    第二次学习笔记
    java学习笔记
    第十四周完成情况
    课程计划进程
    课程设计分工
    JAVA学习笔记(六)
    JAVA学习笔记(五)
  • 原文地址:https://www.cnblogs.com/iloveysm/p/12385944.html
Copyright © 2020-2023  润新知