【数据结构模板】线段树2(加乘 区间修改 区间查询)

本文介绍了一种利用树状数组(也称作二进制指数堆)实现在线更新和区间查询的算法。代码展示了一个完整的C++实现,包括更新区间元素乘法、加法以及查询区间和的功能,适用于处理大规模静态数据的动态查询问题。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
#define maxn 100001
int n,m;
ll mod;
ll a[maxn],tree[maxn<<2],add[maxn<<2],mul[maxn<<2];
ll ls(ll p){
	return p<<1;
}
ll rs(ll p){
	return p<<1|1;
}
void push_up(ll p){
	tree[p]=(tree[ls(p)]+tree[rs(p)]) %mod;
}

void build(ll l,ll r,ll p){
	add[p]=0;
	mul[p]=1;
	
	if(l==r) {tree[p]=a[l];return;}
	
	ll mid=(l+r)>>1;
	build(l,mid,ls(p));
	build(mid+1,r,rs(p));
	push_up(p);
}

void f(ll l,ll r,ll p,ll kadd,ll kmul){
	tree[p]=tree[p]*kmul %mod + (r-l+1)*kadd %mod;
	
	mul[p]=(mul[p]*kmul)%mod;
	add[p]=(add[p]*kmul+kadd)%mod;
}

void push_down(ll l,ll r,ll p){
	ll mid=(l+r)>>1;
	
	f(l,mid,ls(p),add[p],mul[p]);
	f(mid+1,r,rs(p),add[p],mul[p]);
	mul[p]=1;
	add[p]=0;
	return;
}

void update_add(ll nl,ll nr,ll l,ll r,ll p,ll k){
	if(l>=nl && r<=nr){
		tree[p]+=k*(r-l+1) %mod;
		add[p]+=k %mod;
		return;	
	}
	
	push_down(l,r,p);
	
	ll mid=(l+r)>>1;
	if(mid>=nl) update_add(nl,nr,l,mid,ls(p),k);
	if(mid<nr)  update_add(nl,nr,mid+1,r,rs(p),k);
	push_up(p);
}
void update_mul(ll nl,ll nr,ll l,ll r,ll p,ll k){
	if(l>=nl && r<=nr){
		tree[p]=tree[p]*k %mod;
		mul[p]=mul[p]*k%mod;
		add[p]=add[p]*k%mod;
		return;	
	}
	
	push_down(l,r,p);
	
	ll mid=(l+r)>>1;
	if(mid>=nl) update_mul(nl,nr,l,mid,ls(p),k);
	if(mid<nr)  update_mul(nl,nr,mid+1,r,rs(p),k);
	push_up(p);
}

ll query(ll qx,ll qy,ll l,ll r,ll p){
	ll res=0;
	if(l>=qx && r<=qy) return tree[p] %mod;
	
	push_down(l,r,p);
	
	ll mid=(l+r)>>1;
	if(mid>=qx) res+=query(qx,qy,l,mid,ls(p)) %mod;
	if(mid<qy)  res+=query(qx,qy,mid+1,r,rs(p)) %mod;
	return res%mod;
}
int main(){
	cin>>n>>m>>mod;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,n,1);
	while(m--){
		int pd;
		cin>>pd;
		ll x,y,k;
		if(pd==1){
			cin>>x>>y>>k;
			update_mul(x,y,1,n,1,k);
		}
		else if(pd==2){
			cin>>x>>y>>k;
			update_add(x,y,1,n,1,k);
		}
		else if(pd==3){
			cin>>x>>y;
			cout<<query(x,y,1,n,1)<<endl;
		}
	}
	return 0;
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值