P3373 【模板】线段树 2

题目

在这里插入图片描述

思路

作为线段树模板题,这题主要考查了对lazytag以及先乘后加的使用,
线段树详解
因为是模板,所以这里证明略

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+5;
int n,m,p;
int a[maxn];
struct node{
	int v,mul,add;
}st[maxn*4];
//初始化
void init(int root,int l,int r){
	st[root].mul=1,st[root].add=0;
	if(l==r) st[root].v=a[l];
	else { int mid=l+r>>1;init(root*2,l,mid),init(root*2+1,mid+1,r),st[root].v=st[root*2].v+st[root*2+1].v; }
	st[root].v%=p;
	return;
}
void pushdown(int root,int l,int r){
    int mid=(l+r)/2;
    st[root*2].v=(st[root*2].v*st[root].mul+st[root].add*(mid-l+1))%p,st[root*2+1].v=(st[root*2+1].v*st[root].mul+st[root].add*(r-mid))%p,st[root*2].mul=(st[root*2].mul*st[root].mul)%p,st[root*2+1].mul=(st[root*2+1].mul*st[root].mul)%p,st[root*2].add=(st[root*2].add*st[root].mul+st[root].add)%p,st[root*2+1].add=(st[root*2+1].add*st[root].mul+st[root].add)%p,st[root].mul=1,st[root].add=0;
    return;
}
//加
void ud1(int root,int stdl,int stdr,int l,int r,int k){
    if(r<stdl||stdr<l) return;
    if(l<=stdl&&stdr<=r) { st[root].v=(st[root].v*k)%p,st[root].mul=(st[root].mul*k)%p,st[root].add=(st[root].add*k)%p;return; }
    pushdown(root,stdl,stdr);
    int mid=stdl+stdr>>1;
    ud1(root*2,stdl,mid,l,r,k),ud1(root*2+1,mid+1,stdr,l,r,k);
    st[root].v=(st[root*2].v+st[root*2+1].v)%p;
    return;
}
//乘
void ud2(int root,int stdl,int stdr,int l,int r,int k){
    if(r<stdl||stdr<l) return;
    if(l<=stdl&&stdr<=r){
		st[root].add=(st[root].add+k)%p,st[root].v=(st[root].v+k*(stdr-stdl+1))%p;
        return;
    }
    pushdown(root,stdl,stdr);
    int mid=stdl+stdr>>1;
    ud2(root*2,stdl,mid,l,r,k),ud2(root*2+1,mid+1,stdr,l,r,k);
    st[root].v=(st[root*2].v+st[root*2+1].v)%p;
    return;
}
//查询区间和
int 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 mid=(stdl+stdr)/2;
    return (query(root*2,stdl,mid,l,r)+query(root*2+1,mid+1,stdr,l,r))%p;
}
signed main(){
	cin>>n>>m>>p;
    for(int i=1;i<=n;i++) cin>>a[i];
    init(1,1,n);
    while(m--){
        int if_case;cin>>if_case;
        int x,y,k;
        switch (if_case){
        	case 1:cin>>x>>y>>k;ud1(1,1,n,x,y,k);break;
        	case 2:cin>>x>>y>>k;ud2(1,1,n,x,y,k);break;
        	case 3:cin>>x>>y;cout<<query(1,1,n,x,y)<<endl;break;
		}
    }
    return 0;
}

end

完结撒花

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、付费专栏及课程。

余额充值