ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

记一道乘法&加法线段树(模版题)

2021-09-10 17:32:56  阅读:137  来源: 互联网

标签:int 模版 线段 cin seg 加法 mul ll op


P3373 【模板】线段树 2

做法:

两个标记,一个标记是乘,一个是加,每次做乘法时,将前面的加法乘上当前的乘数,然后转移就可以先乘后加

(a*b+c)*d=a*b*d+c*d

如上式,a是原数, 操作顺序是乘b,加c,乘d。

两个标记的变换为 [1,0] => [b,0] => [b,c] => [b*d,c*d]

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int p;
const int MAXN=1e5+5;
ll a[MAXN];
ll seg[MAXN<<2][3];
/*
0:区间和
1:乘
2:加
*/
void build(int i,int l,int r){
    seg[i][1]=1;
    if(l==r){
        seg[i][0]=a[l]%p;
        return;
    }
    int mid=l+(r-l)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    seg[i][0]=seg[i*2][0]+seg[i*2+1][0];
    seg[i][0]%=p;
}

void push_down(int i,int l,int r){
    //先乘,后加
    seg[i*2][1]*=seg[i][1];seg[i*2][1]%=p;
    seg[i*2][2]*=seg[i][1];seg[i*2][2]%=p;
    seg[i*2+1][1]*=seg[i][1];seg[i*2+1][1]%=p;
    seg[i*2+1][2]*=seg[i][1];seg[i*2+1][2]%=p;
    //加
    seg[i*2][2]+=seg[i][2];seg[i*2][2]%=p;
    seg[i*2+1][2]+=seg[i][2];seg[i*2+1][2]%=p;
    int mid=l+(r-l)/2;
    seg[i*2][0]=(seg[i*2][0]*seg[i][1]%p+seg[i][2]*(mid-l+1))%p;
    seg[i*2+1][0]=(seg[i*2+1][0]*seg[i][1]%p+seg[i][2]*(r-mid))%p;
    seg[i][1]=1;
    seg[i][2]=0;
}

void add(int i,int l,int r,int x,int y,int k){//加上k
    if(x<=l&&r<=y){
        seg[i][0]+=1ll*k*(r-l+1);seg[i][0]%=p;
        seg[i][2]+=k;
        return;
    }
    int mid=l+(r-l)/2;
    push_down(i,l,r);
    if(x<=mid) add(i*2,l,mid,x,y,k);
    if(y>mid) add(i*2+1,mid+1,r,x,y,k);
    seg[i][0]=seg[i*2][0]+seg[i*2+1][0];
    seg[i][0]%=p;
}

void mul(int i,int l,int r,int x,int y,int k){//乘k
    if(x<=l&&r<=y){
        seg[i][0]*=k;seg[i][0]%=p;
        seg[i][1]*=k;seg[i][1]%=p;
        seg[i][2]*=k;seg[i][2]%=p;
        return;
    }
    int mid=l+(r-l)/2;
    push_down(i,l,r);
    if(x<=mid) mul(i*2,l,mid,x,y,k);
    if(y>mid) mul(i*2+1,mid+1,r,x,y,k);
    seg[i][0]=seg[i*2][0]+seg[i*2+1][0];
    seg[i][0]%=p;
}

ll query(int i,int l,int r,int x,int y){
    if(r<x||l>y)
        return 0;
    if(x<=l&&r<=y)
        return seg[i][0];
    int mid=l+(r-l)/2;
    push_down(i,l,r);
    return (query(i*2,l,mid,x,y)+query(i*2+1,mid+1,r,x,y))%p;
}

int main(){
    int n,m;
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,n);
    while(m--){
        int op,x,y,k;
        cin>>op>>x>>y;
        if(op==1){
            cin>>k;
            mul(1,1,n,x,y,k);
            continue;
        }
        if(op==2){
            cin>>k;
            add(1,1,n,x,y,k);
            continue;
        }
        cout<<query(1,1,n,x,y)<<endl;
    }

}

 

标签:int,模版,线段,cin,seg,加法,mul,ll,op
来源: https://www.cnblogs.com/xuanzo/p/15252179.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有