扩大
缩小

【模板】 线段树 (支持乘法)

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;
}

 

posted @ 2018-07-18 10:47  luv_letters  阅读(404)  评论(0编辑  收藏  举报
AmazingCounters.com
博文导航目录