线段树模板代码

线段树(区间和)模板代码

本代码测试通过P3368题
如有错误,欢迎指出(我觉得没有,毕竟都AC了,哈哈)

写法一:结构体数组构建线段树

结构体参数解释

  1. lran:节点表示原数组的区间左端下标
  2. rran:节点表示原数组的区间右端下标
  3. lazy:懒惰标记,区间修改时用于标记本节点已被修改,但是其子节点未被修改的点
  4. val:当前节点所表示的数值

函数解释

  1. glson:获取当前节点的左儿子(本代码中,线段树数组的0号下标不放置节点,因此满足 l s o n = f a t h e r ∗ 2 lson=father*2 lson=father2
  2. grson:获取当前节点的右儿子
  3. update:根据当前节点的子节点更新当前节点(节点u)
  4. pushDown:lazy标记下传。(因为本题对区间的操作是累加,因此lazy是可加的,因此只需要在查询的时候下传标记即可,修改区间时无需下传)
#include <iostream>
#define maxn 500010
using namespace std;

struct node {
	int lran, rran, lazy;
	long val;
	node() { lazy = 0; }
};
int arr[maxn] = { 0 };
// 构建线段树数组
node tree[maxn * 4] = {};
inline int glson(int u) { return u << 1; }
inline int grson(int u) { return u << 1 | 1; }
inline void update(int u) { tree[u].val = tree[glson(u)].val + tree[grson(u)].val; }
inline void pushDown(int u) {
	// 如果是叶子节点,无需下传
	if (tree[u].lran == tree[u].rran) {
		tree[u].lazy = 0;
		return;
	}
	// 下传标记
	int lson = glson(u), rson = grson(u);
	tree[lson].lazy += tree[u].lazy;
	tree[rson].lazy += tree[u].lazy;
	// 数值下传
	tree[lson].val += (tree[lson].rran - tree[lson].lran + 1) * tree[u].lazy;
	tree[rson].val += (tree[rson].rran - tree[rson].lran + 1) * tree[u].lazy;
	// 清空当前lazy
	tree[u].lazy = 0;
}
// 建树
void build(int u, int lran, int rran) {
	tree[u].lran = lran, tree[u].rran = rran;
	// 如果是叶子节点
	if (lran == rran) {
		tree[u].val = arr[lran];
		return;
	}
	int mid = lran + rran >> 1;
	build(glson(u), lran, mid);
	build(grson(u), mid + 1, rran);
	update(u);
}
// 单点修改
void add(int u, int pos, int k) {
	// 到达叶子节点
	if (tree[u].lran == tree[u].rran) {
		tree[u].val += k;
		return;
	}
	int mid = tree[u].lran + tree[u].rran >> 1;
	if (pos <= mid) add(glson(u), pos, k);
	else add(grson(u), pos, k);
	update(u);
}
// 区间修改
void modify(int u, int lran, int rran, int k) {
	// cout << "u=" << u << endl;
	if (lran == tree[u].lran && rran == tree[u].rran) {
		tree[u].lazy += k;
		tree[u].val += k * (tree[u].rran - tree[u].lran + 1);
		return;
	}
	int mid = tree[u].lran + tree[u].rran >> 1;
	if (mid >= rran) modify(glson(u), lran, rran, k);
	else if(mid < lran) modify(grson(u), lran, rran, k);
	else {
		modify(glson(u), lran, mid, k);
		modify(grson(u), mid + 1, rran, k);
	}
	update(u);
}
// 区间查询
long search(int u, int lran, int rran) {
	// 当前节点有lazy,下传
	if (tree[u].lazy) pushDown(u);
	// 完全不在区间内
	if (lran < tree[u].lran || rran > tree[u].rran) return 0;
	// 完全包含
	if (lran <= tree[u].lran && rran >= tree[u].rran) return tree[u].val;
	long val = 0;
	// 左区间交
	if (tree[glson(u)].rran >= lran) val += search(glson(u), lran, rran);
	// 右区间交
	if (tree[grson(u)].lran <= rran) val += search(grson(u), lran, rran);
	return val;
}
// 单点查询
long query(int u, int pos) {
	// 当前节点有lazy,下传
	if (tree[u].lazy) pushDown(u);
	if (tree[u].lran == tree[u].rran) return tree[u].val;
	int mid = tree[u].lran + tree[u].rran >> 1;
	if (pos <= mid) return query(glson(u), pos);
	else return query(grson(u), pos);
}
int main() {
	int N, M, L, R, k, idx, op;
	cin >> N >> M;
	for (int i = 0; i < N; ++i) cin >> arr[i];
	// 建立树
	build(1, 0, N - 1);
	for (int i = 0; i < M; ++i) {
		cin >> op;
		// 单点修改
		if (op == 1) {
			cin >> L >> R >> k;
			modify(1, L - 1, R - 1, k);
		}
		// 单点查询
		else {
			cin >> idx;
			cout << query(1, idx - 1) << endl;
		}
	}
	return 0;
}

写法二:指针构建离散线段树

#include <iostream>
#define maxn 500010
using namespace std;

int arr[maxn] = { 0 };
struct node {
	int lran, rran, lazy;
	long val;
	node* lson, * rson;
	node() { lson = nullptr, rson = nullptr, lazy = 0; }
};
inline void update(node* u) { u->val = u->lson->val + u->rson->val; }
inline void pushDown(node* u) {
	// 如果是叶子节点
	if (u->lran == u->rran) {
		u->lazy = 0;
		return;
	}
	// 下传标记
	u->lson->lazy += u->lazy;
	u->rson->lazy += u->lazy;
	// 修改赋值
	u->lson->val += (u->lson->rran - u->lson->lran + 1) * u->lazy;
	u->rson->val += (u->rson->rran - u->rson->lran + 1) * u->lazy;
	// 清空lazy
	u->lazy = 0;
}
// 建树
node* build(int lran, int rran) {
	node* u = new node();
	u->lran = lran, u->rran = rran;
	// 到达叶节点
	if (lran == rran) {
		u->val = arr[lran];
		return u;
	}
	int mid = (lran + rran) >> 1;
	u->lson = build(lran, mid);
	u->rson = build(mid + 1, rran);
	// 更新节点
	update(u);
	return u;
}
// 修改区间
void modify(node* u, int lran, int rran, int k) {
	// 完全覆盖
	if (u->lran == lran && u->rran == rran) {
		u->val += k * (rran - lran + 1);
		u->lazy += k;
		return;
	}
	int mid = (u->lran + u->rran) >> 1;
	if (mid >= rran) {
		modify(u->lson, lran, rran, k);
	}
	else if (mid < lran) {
		modify(u->rson, lran, rran, k);
	}
	else {
		modify(u->lson, lran, mid, k);
		modify(u->rson, mid + 1, rran, k);
	}
	// 更新节点
	update(u);
}
// 单点查询
long query(node* u, int pos) {
	// 下传标记
	if(u->lazy) pushDown(u);
	if (u->lran == u->rran) return u->val;
	int mid = (u->lran + u->rran) >> 1;
	if (pos <= mid) return query(u->lson, pos);
	else return query(u->rson, pos);
}
int main() {
	int N, M, op, L, R, k, idx;
	cin >> N >> M;
	for (int i = 0; i < N; ++i) cin >> arr[i];
	node* head = build(0, N - 1);
	for (int i = 0; i < M; ++i) {
		cin >> op;
		if (op == 1) {
			cin >> L >> R >> k;
			modify(head, L - 1, R - 1, k);
		}
		else {
			cin >> idx;
			cout << query(head, idx - 1) << endl;
		}
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值