線段樹模板

du463發表於2024-03-14

線段樹模板

沉澱了很久,總算是掌握了線段樹的經典模板了。但是還是需要深刻練習才能反覆加深印象呢

//線段樹模板
#include<bits/stdc++.h>
using namespace std;
#define int long long


const int N=1e5+10;
int ans[N*4];
int t1[N*4],t2[N*4];
int a[N];//存放輸入資料
int n,m;
int tag[N*4];



//查詢左右兒子
inline int leftson(int x){
	return x<<1;

}
inline int rightson(int x){
	return x<<1|1;

}

//維護區間關係(字首和,區間最大值,最小值)
void PushSum(int x){
	ans[x]=ans[leftson(x)]+ans[rightson(x)];
}


void PushMax(int x){
	t1[x]=max(t1[leftson(x)],t1[rightson(x)]);
}

void PushMin(int x){
	t2[x]=min(t2[leftson(x)],t2[rightson(x)]);
}

//建樹
void build(int x,int l,int r){
	if(l==r){
		ans[x]=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(leftson(x),l,mid);
	build(rightson(x),mid+1,r);

	PushSum(x);
	// PushMax(x);
	// PushMin(x);
	

}


//區間修改

inline void f(int x,int l,int r,int k){
	tag[x]=tag[x]+k;
	ans[x]=ans[x]+k*(r-l+1);
	//這裡需要區分是整體加k,還是當前區間所有都加k
}

inline void PushDown(int x,int l,int r){
	int mid=(l+r)>>1;
	f(leftson(x),l,mid,tag[x]);
	f(rightson(x),mid+1,r,tag[x]);
	tag[x]=0;

}

inline void  update(int nl,int nr,int l,int r,int x,int k){
	//nl,nr是要修改的區間
	//l,r是當前節點所儲存的區間以及節點的編號
	if(nl<=l&&r<=nr){
		ans[x]+=k*(r-l+1);
		tag[x]+=k;
		return ;
	}
	PushDown(x,l,r);
	int mid=(l+r)>>1;
	if(nl<=mid) update(nl,nr,l,mid,leftson(x),k);
	if(nr>mid) update(nl,nr,mid+1,r,rightson(x),k);
	PushSum(x);

}

//區間查詢

int query(int _x,int _y,int l,int r,int x){
	int res=0;
	if(_x<=l&&r<=_y){
		return ans[x];
	}
	int mid=(l+r)>>1;
	PushDown(x,l,r);
	if(_x<=mid){
		res+=query(_x,_y,l,mid,leftson(x));

	}
	if(_y>mid){
		res+=query(_x,_y,mid+1,r,rightson(x));

	}
	return res;
	
}

void solve(){
	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 op;
		cin>>op;
		if(op==1){
			int x,y,k;
			cin>>x>>y>>k;	
			update(x,y,1,n,1,k);
		}
		else{
			int x,y;
			cin>>x>>y;
			cout<<query(x,y,1,n,1)<<endl;
			
		}
	}
}

signed main(){
	int t=1;
	while(t--){
		solve();
	}
	return 0;

}

相關文章