zoukankan      html  css  js  c++  java
  • 【模板】 线段树 (支持乘法)

    Eg:

    题目描述

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

    1.将某区间每一个数乘上x

    2.将某区间每一个数加上x

    3.求出某区间每一个数的和

    输入输出格式

    输入格式:

    第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

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

    接下来M行每行包含3或4个整数,表示一个操作,具体如下:

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

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

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    17
    2

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=8,M<=10

    对于70%的数据:N<=1000,M<=10000

    对于100%的数据:N<=100000,M<=100000

    (数据已经过加强^_^)

    样例说明:

    故输出应为17、2(40 mod 38=2)

    #include<bits/stdc++.h>
    typedef long long  ll;
    using namespace std;
    int p;
    ll a[100007];
    struct tree{
        ll v, mul, add;
    }st[400028];
    void build (int father ,int l,int r){
        st[father].mul=1;
        st[father].add=0;
        if(l==r) {
            st[father].v=a[l];
        }
        else{
            int m=(l+r)/2;
            build(2*father,l,m);
            build(1+2*father,m+1,r);
            st[father].v=st[father*2].v+st[father*2+1].v;
        }
        st[father].v%=p;
        return ;
    }    
    void pushdown(int father,int l,int r){
        int m=(r+l)/2;
        st[father*2].v=(st[father*2].v*st[father].mul+st[father].add*(m-l+1))%p;
        st[1+father*2].v=(st[father*2+1].v*st[father].mul+st[father].add*(r-m))%p;
        st[father*2].mul=(st[father*2].mul*st[father].mul)%p;
        st[father*2+1].mul=(st[father*2+1].mul*st[father].mul)%p;
        st[father*2].add=(st[father*2].add*st[father].mul+st[father].add)%p;
        st[father*2+1].add=(st[father*2+1].add*st[father].mul+st[father].add)%p;
        st[father].mul=1,st[father].add=0;
        return ;
    }
    void up1(int father ,int stl,int stdr,int l,int r ,ll k){
        if(r<stl ||l>stdr) return ;
        if(stl>=l&&stdr<=r) {
            st[father].v=st[father].v*k%p;
            st[father].mul=st[father].mul*k%p;
            st[father].add=st[father].add*k%p;
            return ;
        }
        pushdown (father , stl , stdr );
        int m=(stdr+stl)/2;
        up1(father*2,stl,m,l,r,k);
        up1(father*2+1 , m+1, stdr, l , r , k);
        st[father].v=(st[father*2].v+st[father*2+1].v)%p;
        return ;
    } //乘法
    void up2(int father ,int stl,int stdr,int l,int r ,ll k){
        if(r<stl ||l>stdr) return ;
        if(stl>=l&&stdr<=r) {
            st[father].add=(st[father].add+k)%p;
            st[father].v=(st[father].v+k*(stdr-stl+1))%p;
            return ;
        }
        pushdown (father , stl , stdr );
        int m=(stdr+stl)/2;
        up2(father*2,stl,m,l,r,k);
        up2(father*2+1 , m+1, stdr, l , r , k);
        st[father].v=(st[father*2].v+st[father*2+1].v)%p;
        return ;
    }
    ll query(int root, int stdl, int stdr, int l, int r){
        if(r<stdl || stdr<l){
            return 0;
        }
        if(l<=stdl && stdr<=r){
            return st[root].v;
        }
        pushdown(root, stdl, stdr);
        int m=(stdl+stdr)/2;
        return (query(root*2, stdl, m, l, r)+query(root*2+1, m+1, stdr, l, r))%p;
    }
    /*int  query(int  father ,int stl,int stdr,int l,int r ,int k){
        if(r<stl ||l>stdr) return 0;
        if(stl>=l&&stdr<=r) {
            return st[father].v;
        }
        pushdown (father , stl , stdr );
        int m=(stdr+stl)/2;
        return (query(father*2,stl,m,l,r)+query(father*2+1,m+1,stdr,l,r))%p;
    }*/
    int main(){
        ios::sync_with_stdio(false);
        int m,n;
        cin>>n>>m>>p;
        for(int i=1;i<=n;i++) cin>>a[i];
        build (1,1,n);
        while (m--){
            int qwq,x,y;
            ll k;
            cin>>qwq;
            if(qwq==1){
                cin>>x>>y>>k;
                up1(1,1,n,x,y,k);
            }
            else if(qwq==2) {
                cin>>x>>y>>k;
                up2(1,1,n,x,y,k);
            }
            else {
                cin>>x>>y;
                cout<<query(1,1,n,x,y)<<endl;
            }
        }    
        return 0;
    }
  • 相关阅读:
    Oracle
    Windows
    Ajax
    Ext JS
    JavaScript
    Linux中查看各文件夹大小命令du
    本地文件上传到Linux服务器的几种方法
    Mysql线程状态
    把mysql里面的一些状态输出到文件里面显示
    linux修改磁盘调度方法
  • 原文地址:https://www.cnblogs.com/luv-letters/p/9327876.html
Copyright © 2011-2022 走看看