线段树模板知识整理(懒标记、结构体)

一套适合自己风格的线段树模板整理

经过一天半的煎熬,刚开始头疼的不行,实在想不通,到现在线段树终于像是入坑了,在网上找了好多资料,终于能结合人家的写一套适合我风格的模板。现在来记录下我的一些理解和代码,在以后含糊的时候返回来看看。推荐视频:b站 正月点灯笼 思路很容易理解,但代码难模仿,SWPU-ACM的代码还是容易模仿的。还有强大的CSDN上有很多详细的讲解。
我的代码主要时使用一个结构体代表树,我觉得用结构体能够更好地展示这个树的特点,和每一个结点的内容。在写的过程中保存了好多测试截图的,不过现在懒得上传了。。。该有的注释我加到代码旁边。
以下函数包括:

void build(int rt, int l, int r)			(建树)
rt代表每次要创建的根节点,l和r为这个树上表示的左右端点值
void update(int rt, int p, int val)			(单点修改)
rt仍然为树的根节点,p为要修改的位置,val为新值
void update(int rt, int l, int r, int c)	(区间修改)
此函数作用为在l到r这一区间内,对每个值增加c
int query(int rt, int p)					(单点查询)
查询p点的值
int query(int rt, int l, int r)				(区间查询)
查询l到r这一区间内的信息,可查询sum,max,min···
void down(int rt)							 (懒标记下传)
当用到懒标记(区间修改)之后,再次进行区间或者单点查询时,就需要进行懒标记下传。

线段树模板如下(懒标记):

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define lson  rt<<1, l, mid
#define rson  rt<<1|1, mid+1, r 
using namespace std;
const int maxn = 1e5;
int a[maxn];
struct node{
	int l, r;
	int sum;
	int lazy;
}tree[4*maxn];
int n, m;
void up(int rt){
	tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
void down(int rt){
	if(tree[rt].lazy){
		tree[rt<<1].lazy += tree[rt].lazy;
		tree[rt<<1|1].lazy += tree[rt].lazy;
		tree[rt<<1].sum += tree[rt].lazy * (tree[rt<<1].r-tree[rt<<1].l+1);
		tree[rt<<1|1].sum += tree[rt].lazy * (tree[rt<<1|1].r-tree[rt<<1|1].l+1);
		tree[rt].lazy = 0;
	}
}
void build(int rt, int l, int r){
	tree[rt].l = l, tree[rt].r = r;
	tree[rt].lazy = 0;
	// 如果当前节点记录的区间只有一个值,说明找到了叶子结点,直接赋值
	// 否则递归构造左右子树,最后回溯的时候给当前节点赋值
	if(l == r){
		tree[rt].sum = a[l];
		return ;
	}
	int mid = (l + r) >> 1;
	build(rt<<1, l, mid);
	build(rt<<1|1, mid+1, r);
	tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
/*
void update(int rt, int p, int val){
	// 单点修改 
	// 这个if语句就是判断是否到达叶子结点 
	if(tree[rt].l == tree[rt].r){
		tree[rt].sum = val;
		return ;
	}
	int mid = (tree[rt].l + tree[rt].r) >> 1;
	if(p <= mid)	update(rt<<1, p, val);
	else	 		update(rt<<1|1, p, val);
	tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
*/
void update(int rt, int l, int r, int c){
	// 区间修改,同时增加c
	if(tree[rt].l >= l && tree[rt].r <= r){
		tree[rt].lazy += c;		// 记录这个标记
		tree[rt].sum += c * (tree[rt].r - tree[rt].l + 1);
		return ; 
	}
	down(rt);
	int mid = (tree[rt].l + tree[rt].r) >> 1;
	if(mid >= r)		update(rt<<1, l, r, c);
	else if(mid < l)	update(rt<<1|1, l, r, c);
	else{
		update(rt<<1, l, mid, c);
		update(rt<<1|1, mid+1, r, c);
	}
	tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
/*
int query(int rt, int p){
	// 单点查询
	if(tree[rt].l == tree[rt].r)	
		return tree[rt].sum;
	int mid = (tree[rt].l + tree[rt].r) >> 1; 
//	down(rt);
	int ans;
	if(p <= mid)	ans = query(rt<<1, p);
	else	ans = query(rt<<1|1, p);
	return ans;
}
*/
int query(int rt, int l, int r){
	// 区间查询 
	if(tree[rt].l >= l && tree[rt].r <= r)
		return tree[rt].sum;
	down(rt);		// 用到lazy数组 
	int mid = (tree[rt].l + tree[rt].r) >> 1; 
	if(r <= mid)		return query(rt<<1, l, r);
	else if(mid < l)	return query(rt<<1|1, l, r);
	else
		return query(rt<<1, l, mid) + query(rt<<1|1, mid+1, r);
}
int main(){
	cin >> n ;
	for(int i = 1; i <= n; i++)	
		cin >> a[i];
	build(1, 1, n);
	for(int i = 1; i <= 15; i++)	
		cout << tree[i].sum <<" "<< tree[i].lazy << endl;
		cout << query(1, 3, 6) << endl;		 
	return 0;
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值