【模板】线段树

1.只维护加法

【模板】线段树 1

#include<cstdio>
using namespace std;
typedef long long ll; 
const int NN = 1e5+8;
int n,m;
ll a[NN];
struct seg{
	ll l,r;
	ll sum,add;
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define sum(x) tree[x].sum
	#define add(x) tree[x].add
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
}tree[NN<<2]; 
void addlz(ll x,ll d){
	add(x) += d;sum(x) += d*(r(x)-l(x)+1);
}
void pushdown(int x){
	addlz(ls(x),add(x));addlz(rs(x),add(x));
	add(x) = 0;
	return;
}
void pushup(int x){
	sum(x) = sum(ls(x)) + sum(rs(x));
}
void build(int p,int l,int r){
	l(p) = l;r(p) = r;
	if(l == r){sum(p) = a[l];return;}
	int mid = (l+r)>>1;
	build(ls(p),l,mid);
	build(rs(p),mid+1,r);
	pushup(p);
}
void change(ll p,ll l,ll r,ll d){
	if(l <= l(p) && r(p) <= r){addlz(p,d);return;}
	pushdown(p);
	ll mid = (l(p)+r(p))>>1;
	if(l <= mid) change(ls(p),l,r,d);
	if(r > mid) change(rs(p),l,r,d);
	pushup(p);
}
ll query(int p,int l,int r){
	if(l <= l(p) && r(p) <= r){return sum(p);}
	ll mid = (l(p)+r(p))>>1;
	pushdown(p);
	ll res = 0;
	if(l <= mid) res += query(ls(p),l,r);
	if(r > mid) res += query(rs(p),l,r);
	return res;
} 
int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++)
		scanf("%lld",&a[i]);
	build(1,1,m);
	for(int i = 1,type,a,b,c; i <= m; i++){
		scanf("%d",&type);
		if(type == 1){
			scanf("%d%d%d",&a,&b,&c);
			change(1,a,b,c);
		}
		if(type == 2){
			scanf("%d%d",&a,&b);
			printf("%lld\n",query(1,a,b));
		}
//		print(1);
	}
} 

2. 维护加法和乘法

【模板】线段树 2

#include<cstdio>
using namespace std;
typedef long long ll; 
const int NN = 1e5+8;
int n,m,mod;
ll a[NN];
inline ll Calc(const ll a,const ll b){ll res = a+b;return res-(res>=mod?mod:0);}//加法取模封装
inline ll Mult(const ll a, const ll b){return a*b%mod;}//乘法取模封装
struct seg{
	ll l,r;//记录区间左右端点
	ll sum,add,mul;//sum为区间和,add为加法标记,mul为乘法标记
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define sum(x) tree[x].sum
	#define add(x) tree[x].add
	#define mul(x) tree[x].mul
	#define ls(x) x << 1
	#define rs(x) x << 1 | 1
}tree[NN<<2]; 
void addlz(ll x,ll d){
	add(x) = Calc(add(x),d);sum(x) = Calc(sum(x),Mult(d,r(x)-l(x)+1));
}//对节点进行加法操作
void mullz(ll x,ll d){
	mul(x) = Mult(mul(x),d);sum(x) = Mult(sum(x),d);add(x) = Mult(add(x),d);
}//对节点进行乘法操作
void pushdown(int x){
	mullz(ls(x),mul(x));mullz(rs(x),mul(x));
	addlz(ls(x),add(x));addlz(rs(x),add(x));
	add(x) = 0; mul(x) = 1;
	return;
}//下传标记
void pushup(int x){
	sum(x) = Calc(sum(ls(x)) , sum(rs(x)));
}//上传结果
void build(int p,int l,int r){
	mul(p) = 1;
	l(p) = l;r(p) = r;
	if(l == r){sum(p) = a[l];return;}
	int mid = (l+r)>>1;
	build(ls(p),l,mid);
	build(rs(p),mid+1,r);
	pushup(p);
}//建树
void change_add(ll p,ll l,ll r,ll d){
	if(l <= l(p) && r(p) <= r){addlz(p,d);return;}
	pushdown(p);
	ll mid = (l(p)+r(p))>>1;
	if(l <= mid) change_add(ls(p),l,r,d);
	if(r > mid) change_add(rs(p),l,r,d);
	pushup(p);
}//区间加(l == r 时为单点加)
void change_mul(ll p,ll l,ll r,ll d){
	if(l <= l(p) && r(p) <= r){mullz(p,d);return;}
	pushdown(p);
	ll mid = (l(p)+r(p))>>1;
	if(l <= mid) change_mul(ls(p),l,r,d);
	if(r > mid) change_mul(rs(p),l,r,d);
	pushup(p);
}//区间乘(l == r时为单点乘)
ll query(int p,int l,int r){
	if(l <= l(p) && r(p) <= r){return sum(p);}
	ll mid = (l(p)+r(p))>>1;
	pushdown(p);
	ll res = 0;
	if(l <= mid) res = Calc(res,query(ls(p),l,r));
	if(r > mid) res = Calc(res,query(rs(p),l,r));
	return res;
} //区间查询
//void print(ll p){
//	printf("%lld [%lld,%lld] sum:%lld add:%lld mul:%lld\n",p,l(p),r(p),sum(p),add(p),mul(p));
//	if(l(p) == r(p))return;
//	print(ls(p));
//	print(rs(p));
//} 此为调试语句
int main(){
	scanf("%d%d%d",&n,&m,&mod);
	for(int i = 1; i <= n; i++)
		scanf("%lld",&a[i]);
	build(1,1,m);
//	print(1);
	for(int i = 1,type,a,b,c; i <= m; i++){
		scanf("%d",&type);
		if(type == 1){
			scanf("%d%d%d",&a,&b,&c);
			change_mul(1,a,b,c);
		}
		else if(type == 2){
			scanf("%d%d%d",&a,&b,&c);
			change_add(1,a,b,c);
		}
		else if(type == 3){
			scanf("%d%d",&a,&b);
			printf("%lld\n",query(1,a,b));
		}
//		print(1);
	}
} 
posted @ 2023-01-13 15:58  ricky_lin  阅读(14)  评论(0编辑  收藏  举报