P3373 【模板】线段树 2

P3373 【模板】线段树 2
提交
63.01k
通过
19.89k
时间限制
1.00s
内存限制
125.00MB
提交答案
加入收藏
题目提供者
HansBug
难度
普及+/提高
历史分数
100
提交记录 查看题解
标签
高性能
进入讨论版
相关讨论
推荐题目
展开
题目描述
如题,已知一个数列,你需要进行下面三种操作:

将某区间每一个数乘上 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 的结果。

输入输出样例

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=100005;
ll a[maxn<<2],addtag[maxn],multag[maxn],aa[maxn];
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
ll mod,n,m;
void build(ll rt,ll l,ll r){
    addtag[rt]=0;
    multag[rt]=1;
    if(l==r){
        a[rt]=aa[l]%mod;
        return ;
    }
   ll mid=(l+r)>>1;
    build(lson);
    build(rson);
    a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
void move(ll rt,ll l,ll r,ll mt,ll at){
     a[rt]=(mt*a[rt]+(r-l+1)*at)%mod;
     multag[rt]=(multag[rt]*mt)%mod;
     addtag[rt]=(addtag[rt]*mt+at)%mod;
}
void pushdown(ll rt,ll l,ll r){
   ll mid=(l+r)>>1;
    move(lson,multag[rt],addtag[rt]);
    move(rson,multag[rt],addtag[rt]);
    addtag[rt]=0;
    multag[rt]=1;
}
void  mutupdate(ll ql,ll qr,ll rt,ll l ,ll r,ll k){
    if(ql<=l&&r<=qr){
        a[rt]=(a[rt]*k)%mod;
        multag[rt]=(multag[rt]*k)%mod;
        addtag[rt]=(addtag[rt]*k)%mod;
        return ;
    }
    pushdown(rt,l,r);
    ll mid=(l+r)>>1;
    if(ql<=mid){
        mutupdate(ql,qr,lson,k);
    }
    if(mid<qr){
        mutupdate(ql,qr,rson,k);
    }
    a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
void  addupdate(ll ql,ll qr,ll rt,ll l ,ll r,ll k){
    if(ql<=l&&r<=qr){
        a[rt]=(a[rt]+(r-l+1)*k)%mod;
        addtag[rt]=(addtag[rt]+k)%mod;
        return ;
    }
    pushdown(rt,l,r);
    ll mid=(l+r)>>1;
    if(ql<=mid){
        addupdate(ql,qr,lson,k);
    }
    if(mid<qr){
        addupdate(ql,qr,rson,k);
    }
    a[rt]=(a[rt<<1]+a[rt<<1|1])%mod;
}
ll  query(ll ql,ll  qr,ll rt,ll l,ll r){
    if(ql<=l&&r<=qr){
        return a[rt]%mod;
    }
    pushdown(rt,l,r);
    ll mid=(l+r)>>1;
    ll ans=0;
    if(ql<=mid){
        ans=(ans+query(ql,qr,lson))%mod;
    }
    if(mid<qr){
        ans=(ans+query(ql,qr,rson))%mod;
    }
    return ans%mod;
}
int main(){
    cin>>n>>m>>mod;
    for(int i=1;i<=n;i++){
    	cin>>aa[i];
	}
    build(1,1,n);
    while(m--){
        ll x,y,z,w;
        cin>>x;
        if(x==1){
            cin>>y>>z>>w;
            mutupdate(y,z,1,1,n,w%mod);
        }
        if(x==2){
            cin>>y>>z>>w;
            addupdate(y,z,1,1,n,w%mod);
        }
        if(x==3){
            cin>>y>>z;
            cout<<query(y,z,1,1,n)<<endl;
        }
    }
   return 0;
}
ACM线段树模板C ```c #include<bits/stdc++.h> using namespace std; const int N=1e5+5;//数组开大一点 int n,m; int a[N]; struct node{ int l,r;//左右端点 int sum,lazy;//区间和和懒标记 }t[N*4]; void up(int p){//向上更新 t[p].sum=t[p<<1].sum+t[p<<1|1].sum; } void down(int p){//向下更新 if(t[p].lazy){ t[p<<1].lazy+=t[p].lazy; t[p<<1|1].lazy+=t[p].lazy; t[p<<1].sum+=t[p].lazy*(t[p<<1].r-t[p<<1].l+1); t[p<<1|1].sum+=t[p].lazy*(t[p<<1|1].r-t[p<<1|1].l+1); t[p].lazy=0; } } void build(int p,int l,int r){//建树 t[p].l=l,t[p].r=r; if(l==r){ t[p].sum=a[l]; return; } int mid=(l+r)/2; build(p<<1,l,mid); build(p<<1|1,mid+1,r); up(p); } void change(int p,int l,int r,int k){//单点修改 if(t[p].l==t[p].r){ t[p].sum=k; return; } down(p); int mid=(t[p].l+t[p].r)/2; if(r<=mid) change(p<<1,l,r,k); else if(l>mid) change(p<<1|1,l,r,k); else{ change(p<<1,l,mid,k); change(p<<1|1,mid+1,r,k); } up(p); } void add(int p,int l,int r,int k){//区间修改 if(t[p].l>=l&&t[p].r<=r){ t[p].sum+=k*(t[p].r-t[p].l+1); t[p].lazy+=k; return; } down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid) add(p<<1,l,r,k); if(r>mid) add(p<<1|1,l,r,k); up(p); } int query(int p,int l,int r){//区间查询 if(t[p].l>=l&&t[p].r<=r) return t[p].sum; down(p); int mid=(t[p].l+t[p].r)/2,ans=0; if(l<=mid) ans+=query(p<<1,l,r); if(r>mid) ans+=query(p<<1|1,l,r); return ans; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); for(int i=1;i<=m;i++){ int opt,x,y,k; cin>>opt; if(opt==1){ cin>>x>>y>>k; add(1,x,y,k); } if(opt==2){ cin>>x>>y; cout<<query(1,x,y)<<endl; } if(opt==3){ cin>>x>>k; change(1,x,x,k); } } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值