线段树模板

一、模板

#define lc(p) p << 1         // 左孩子 
#define rc(p) p << 1 | 1     // 右孩子 
const int MAX = 5e5 + 5;     // 数列元素最大个数 
ll n, m, w[MAX];             // n -- 数列元素个数; m -- 操作数; w[i] -- 第i个元素的值 
struct {int l, r; ll sum, tag;} tree[MAX << 2]; // 一般开元素个数的4倍数组 
// 边界为[l, r]; sum -- 区间和; tag -- 懒标记 

void pushup(int p)
{
	tree[p].sum = tree[lc(p)].sum + tree[rc(p)].sum; // 用区间p的左孩子和右孩子的值更新该区间的值 
}

void pushdown(int p)
{
	if (tree[p].tag) // 向下传递懒标记 
	{
		tree[lc(p)].sum += (tree[lc(p)].r - tree[lc(p)].l + 1) * tree[p].tag;
		tree[lc(p)].tag += tree[p].tag;
		
		tree[rc(p)].sum += (tree[rc(p)].r - tree[rc(p)].l + 1) * tree[p].tag;
		tree[rc(p)].tag += tree[p].tag;
		
		tree[p].tag = 0;
	}
}

void build(int p, int l, int r)
{
	tree[p] = {l, r, w[l], 0};
	if (l == r)    return;
	
	int m = l + r >> 1;          // 递归建立左、右子树 
	build(lc(p), l, m);
	build(rc(p), m + 1, r);
	
	pushup(p); 
}

void update(int p, int x, int y, int k)
{
	if (x <= tree[p].l && tree[p].r <= y)
	{
		tree[p].sum += (tree[p].r - tree[p].l + 1) * k;
		tree[p].tag += k;
		return;
	}
	
	pushdown(p);
	
	int m = tree[p].l + tree[p].r >> 1;
	if (x <= m)    update(lc(p), x, y, k);
	if (y > m)    update(rc(p), x, y, k);
	
	pushup(p);
}

ll query(int p, int x, int y)
{
	if (x <= tree[p].l && tree[p].r <= y)
		return tree[p].sum;
		
	pushdown(p);
	
	int m = tree[p].l + tree[p].r >> 1;
	ll sum = 0;
	if (x <= m)    sum += query(lc(p), x, y);
	if (y > m)    sum += query(rc(p), x, y);
	
	return sum;
}

二、相关例题

P3374 【模板】树状数组 1

P3372 【模板】线段树 1

posted @ 2024-05-22 15:12  ltign  阅读(19)  评论(0)    收藏  举报