线段树(模板)

#include
using namespace std;
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define maxn 100005
int n,q;
int a[maxn];
struct node{
	int val,lazy;
}s[maxn*4];
void push_up(int rt){// push_up函数更新节点信息,这里以求和为例 
	s[rt].val=s[rt*2].val+s[rt*2+1].val;
}
void build(int l,int r,int rt){//构造根为rt,A区间为[l,r]线段树 
	s[rt].lazy=0;//懒标记初始化 
	if(l==r){//叶子节点 
		s[rt].val=a[l];
		return ;
	}
	int mid=(l+r)/2;
	build(l,mid,rt*2);//递归构造左子树 
	build(mid+1,r,rt*2+1);//递归构造右子树 
	push_up(rt);//回溯,向上更新 
}
//ln,rn 分别为左子树和右子树的区间大小 
void push_down(int rt,int ln,int rn){
	if(s[rt].lazy){//下推标记 
		s[rt*2].val+=s[rt].lazy*ln;
		s[rt*2+1].val+=s[rt].lazy*rn;
		s[rt*2].lazy+=s[rt].lazy;
		s[rt*2+1].lazy+=s[rt].lazy;
		s[rt].lazy=0;//清除本节点标记 
	}
}
//l,r表示当前节点区间,rt表示当前线段树的根节点标号 
void update1(int L,int C,int l,int r,int rt){//单点修改 
	if(l==r){//叶子节点,直接修改 
		s[rt].val+=C;
		return ;
	}
	int mid=(l+r)/2;
	if(L<=mid) update1(L,C,l,mid,rt*2);
	else update1(L,C,mid+1,r,rt*2+1);
	push_up(rt);//回溯,向上更新 
} 
void update(int L,int R,int C,int l,int r,int rt){//区间更新 
	if(L<=l && r<=R){
		s[rt].val+=C*(r-l+1);//更新数字和,向上保持正确 
		s[rt].lazy+=C;//累加(看需求,这里是累加) 
		return ;
	}
	if(L>r || Rmid) update(L,R,C,mid+1,r,rt*2+1);
	push_up(rt);//更新本节点信息 
}
int query(int L,int R,int l,int r,int rt){//区间查询 
	if(L<=l && r<=R) return s[rt].val; //在区间内直接返回 
	if(L>r || R> n >> q;
	for(int i=1;i<=n;i++) cin >> a[i];
	build(1,n,1);//建树 
	while(q--){
		int op,x,y,k;
		cin >> op >> x >> y;
		if(op==1){//op==1时,在下标[x,y]的数上加 k 
			cin >> k;
			update(x,y,k,1,n,1);
		}else{//op==2时,查询 下标[x,y]的数之和 
			cout << query(x,y,1,n,1) << endl;
		}
	}
	return 0;
}

你可能感兴趣的:(线段树)