Light Segment Tree

2026.05   C++ Segment Tree Lazy Propagation

写线段树的时候维护节点,指针,层级是一件很讨厌的事。开成标准 $2^n$ 大小,就可以直接计算算出层级位置,而不需要使用树状结构来维护,只需要一个类 ST 表数据结构即可。 这是一份按层存储的线段树模板,使用 st[i][j]lazy[i][j] 表示长度为 $2^i$ 的第 $j$ 个区间节点的区间和与懒惰传播数。区间采用左闭右开 [l, r) 的 0 base 写法。

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 1 << 19;	// 524288 > 3e5 


void work(){
	vector<i64> a(N);
//	vector<vector<i64>> st(20, vector<i64>(N)); 改用动态建树
	vector<vector<i64>> st, lazy;
	
	for(int x = N; x; x = x >> 1){
		st.push_back(vector<i64>(x, 0));
		x = x >> 1;
	}
	lazy = st; 
	
#define x getx(l,r)
#define y gety(l,r)
#define mid (l+r)/2
	
	// 左闭右开 0 base
	// 规定st/lazy[i][j] 表示 [(1<<i * j, 1<<i * (j+1) ) 	
	auto getx = [&](int l, int r)-> int{return log2(r-l);};
	auto gety = [&](int l, int r)-> int{return l / (r - l);};
	
	// 用左右儿子更新当前节点
	auto pushup = [&](int l, int r) -> void {
		st[x][y] = st[getx(l, mid)][gety(l, mid)] + st[getx(mid, r)][gety(mid, r)];
	};
	
	// 给当前节点打懒标记
	auto apply = [&](int l, int r, i64 val) -> void {
		st[x][y] += val * (r - l);
		lazy[x][y] += val;
	};
	
	// 下传懒标记
	auto pushdown = [&](int l, int r) -> void {
		if (lazy[x][y] == 0 || r - l == 1) return;
		i64 val = lazy[x][y];
		apply(l, mid, val);
		apply(mid, r, val);
		lazy[x][y] = 0;
	};
	
	// 建树
	auto build = [&](auto self, int l, int r) -> void {
		if (r-l == 1) {
			st[0][l] = a[l];
			return;
		}
		self(self, l, mid);
		self(self, mid, r);
		pushup(l, r);
	};	
	
	// 区间加:[ql, qr) += val
	auto update = [&](auto self, int l, int r, int ql, int qr, i64 val) -> void {
		if (qr <= l || r <= ql) return;
		
		if (ql <= l && r <= qr) {
			apply(l, r, val);
			return;
		}
		pushdown(l, r);
		self(self, l, mid, ql, qr, val);
		self(self, mid, r, ql, qr, val);
		pushup(l, r);
	};
	
	// 区间查询:[ql, qr) 的和
	auto query = [&](auto self, int l, int r, int ql, int qr) -> i64 {
		if (qr <= l || r <= ql) return 0;
		if (ql <= l && r <= qr) return st[x][y];
		pushdown(l, r);
		return self(self, l, mid, ql, qr) + self(self, mid, r, ql, qr);
	};
	
#undef x
#undef y
#undef mid
	
}

int main(){
	ios::sync_with_stdio(false);
	freopen("test.txt", "r", stdin);
	cin.tie(0);
	int T = 1;
	while(T--){
		work();
	} 
	return 0;
}