线段树模板

题目:线段树 1


代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
using namespace std;

#define ll long long
#define maxn 100000

int n,m;
ll a[maxn+5];
ll Sum[4*maxn+5];

int X,Y;
ll add[4*maxn+5]= {0};	//标记 

void build_tree(int o,int L,int R) {	//建树
	if(L==R) {	//叶子节点
		Sum[o]=a[L];
		return ;
	}
	int lson=o*2,rson=o*2+1;
	int mid=(L+R)/2;
	build_tree(lson,L,mid),build_tree(rson,mid+1,R);
	Sum[o]=Sum[lson]+Sum[rson];
	return ;
}

void update(int o,int L,int R,ll v) {	//修改 
	int mid=(L+R)/2;
	int lson=2*o,rson=2*o+1;
	if(X<=L&&R<=Y) {	//边界,即线段被查询的区间完全覆盖
		add[o]+=v;
	} else {
		if(X<=mid) update(lson,L,mid,v);
		if(Y>mid) update(rson,mid+1,R,v);
	}
	if(R>L) Sum[o]=Sum[lson]+Sum[rson];	//有子树 
	else Sum[o]=a[L];	//叶子结点 
	Sum[o]+=(R-L+1)*add[o]; 
}

ll s;
void query(int o,int L,int R,ll Add){	//查询 
	int mid=(L+R)/2;
	int lson=2*o,rson=2*o+1;
	if(X<=L&&R<=Y) {	//边界
		s=s+Sum[o]+(R-L+1)*Add;
		return ;
	}
	if(X<=mid) query(lson,L,mid,Add+add[o]);	//将当前节点的标记向下传递 
	if(Y>mid) query(rson,mid+1,R,Add+add[o]);
}

int main() {
	scanf("%d%d",&n,&m);

	for(int i=1; i<=n; i++) {
		ll x;
		scanf("%lld",&x);
		a[i]=x;
	}

	build_tree(1,1,n);

	for(int i=1; i<=m; i++) {
		int opr;
		scanf("%d",&opr);
		if(opr==1) {
			ll v;
			scanf("%d%d%lld",&X,&Y,&v);
			if(X>Y) swap(X,Y);
			update(1,1,n,v);
		} else {
			scanf("%d%d",&X,&Y);
			if(X>Y) swap(X,Y);
			s=0;
			query(1,1,n,0);
			printf("%lld\n",s);
		}
	}
	return 0;
}


题目:线段树 2


代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
using namespace std;

#define ll long long
#define maxn 100000

ll n,m,P;
ll a[maxn+5]= {0};
ll Sum[4*maxn+5]= {0};

ll X,Y;
ll add[4*maxn+5]= {0};
ll mul[4*maxn+5]= {0};

void build_tree(ll o,ll L,ll R) {	//建树
	add[o]=0,mul[o]=1;
	if(L==R) {
		Sum[o]=a[L];
		return ;
	}
	ll lson=o*2,rson=o*2+1;
	ll mid=(L+R)/2;
	build_tree(lson,L,mid),build_tree(rson,mid+1,R);
	Sum[o]=(Sum[lson]+Sum[rson])%P;
	return ;
}

void push_down(ll o,ll lson,ll rson,ll L,ll R) {	//下移标记
	if(!add[o]&&mul[o]==1) return ;
	ll mid=(L+R)/2;
	mul[lson]=mul[lson]*mul[o]%P;
	mul[rson]=mul[rson]*mul[o]%P;
	add[lson]=(add[lson]*mul[o]+add[o])%P;
	add[rson]=(add[rson]*mul[o]+add[o])%P;
	Sum[lson]=(Sum[lson]*mul[o]+add[o]*(mid-L+1))%P;
	Sum[rson]=(Sum[rson]*mul[o]+add[o]*(R-mid))%P;
	mul[o]=1,add[o]=0;
	return ;
}

void update_add(ll o,ll L,ll R,ll v) {	//加法
	ll mid=(L+R)/2;
	ll lson=2*o,rson=2*o+1;
	if(X<=L&&R<=Y) {
		add[o]=(add[o]+v)%P;
		Sum[o]=(Sum[o]+(R-L+1)*v)%P;
	} else {
		push_down(o,lson,rson,L,R);
		if(X<=mid) update_add(lson,L,mid,v);
		if(Y>mid) update_add(rson,mid+1,R,v);
		Sum[o]=(Sum[lson]+Sum[rson])%P;
	}
}

void update_mul(ll o,ll L,ll R,ll v) {	//乘法
	ll mid=(L+R)/2;
	ll lson=2*o,rson=2*o+1;
	if(X<=L&&R<=Y) {
		mul[o]=mul[o]*v%P;
		add[o]=add[o]*v%P;
		Sum[o]=Sum[o]*v%P;
	} else {
		push_down(o,lson,rson,L,R);
		if(X<=mid) update_mul(lson,L,mid,v);
		if(Y>mid) update_mul(rson,mid+1,R,v);
		Sum[o]=(Sum[lson]+Sum[rson])%P;
	}
}

ll s;
ll query(ll o,ll L,ll R) {	//查询
	ll mid=(L+R)/2;
	ll lson=2*o,rson=2*o+1;
	if(X<=L&&R<=Y) {	//边界
		return Sum[o];
	}

	push_down(o,lson,rson,L,R);
	ll sum=0;
	if(X<=mid) sum+=query(lson,L,mid);
	if(Y>mid) sum+=query(rson,mid+1,R);
	return sum%P;
}

int main() {
	scanf("%lld%lld%lld",&n,&m,&P);

	for(ll i=1; i<=n; i++) {
		ll x;
		scanf("%lld",&x);
		a[i]=x;
	}

	build_tree(1,1,n);

	for(ll i=1; i<=m; i++) {
		ll opr;
		scanf("%lld",&opr);
		if(opr==1) {
			ll v;
			scanf("%lld%lld%lld",&X,&Y,&v);
			if(X>Y) swap(X,Y);
			update_mul(1,1,n,v);
		}
		if(opr==2) {
			ll v;
			scanf("%lld%lld%lld",&X,&Y,&v);
			if(X>Y) swap(X,Y);
			update_add(1,1,n,v);
		}
		if(opr==3) {
			scanf("%lld%lld",&X,&Y);
			if(X>Y) swap(X,Y);
			s=query(1,1,n);
			printf("%lld\n",s%P);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值