浅谈线段树

线段树是一种数据结构,常用于处理区间查询和更新问题。本文通过多个练习介绍了线段树的基本构造思想和应用,包括计算线段覆盖的总长度、统计不同颜色线段的数量以及线段染色后的段数。线段树通过维护每个节点的附加信息,如覆盖状态和颜色,实现了高效的问题解决。
摘要由CSDN通过智能技术生成

线段树

在一类问题中,我们需要经常处理可以映射在一个坐标轴上的一些固定线段,例如说映射在OX轴上的线段。由于线段是可以互相覆盖的,有时需要动态地取线段的并,例如取得并区间的总长度,或者并区间的个数等等。一个线段是对应于一个区间的,因此线段树也可以叫做区间树。

线段树的构造思想

线段树是一棵二叉树,树中的每一个结点表示了一个区间[a,b]。每一个叶子节点表示了一个单位区间。对于每一个非叶结点所表示的结点[a,b],其左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b]。

在这里插入图片描述
线段树的运用

线段树的每个节点上往往都增加了一些其他的域。在这些域中保存了某种动态维护的信息,视不同情况而定。这些域使得线段树具有极大的灵活性,可以适应不同的需求。


练习一:

题目描述:
桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?在这里插入图片描述
样例输入:

20    //桌面总宽度
4     //盒子数量
1 5 
3 8
7 10
13 19

样例输出:

15

分析
抽象化题目:x轴上有若干条线段,求线段覆盖的总长度。
在这里插入图片描述
对于线段树,我们将每一个节点增加一个域,
0表示这一区间没有被完全覆盖,1表示这一区间被完全覆盖。

那我们将这个域设置好后,统计总共覆盖的长度其实就简单了,
以二叉树的遍历方式,判断每一个节点的域是否为一,如果为1我们就统计一下长度,就欧了。

如果当前节点为一,就不能再往下遍历,因为它的子节点是包括在当前节点里面的

插入算法(设置域)

void insert(int x, int l, int r, int a, int b)
{
   
	int mid=(l + r) >> 1;
	if(tree[x]) return ;  //如果已设置了
	if((l == a) && (r == b)) tree[x]=1; //完全被覆盖
	else if(b <= mid) insert(2 * x, l, mid, a, b);  //区间在左边
	else if(a >= mid) insert(2 * x + 1, mid, r, a, b); //区间在右边
	else //区间在左右两边都有覆盖。例:左(3,4) 右(4,6) 插入(3,5)
		insert(2 * x, l, mid, a, mid), //二分
		insert(2 * x + 1, mid, r, mid, b);
}

统计算法

void ccount(int x, int l, int r)
{
   
	int mid=(l + r) >> 1;
	if(tree[x]) ans+=(r - l);
	else if(l+1<r) //当前节点还包括多个点,想(3,4)就不能搜下去了
		ccount(2 * x, l, mid),
		ccount(2 *x + 1, mid, r);
}
注意:count在c++中是关键字,所以不能将其命名为函数名

code:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define ll long long

using namespace std;

const int MAX=2147483647;
const int N=3e5+10;
int n, num, l, r, tree[N], ans; 

void insert(int x, int l, int r, int a, int b)
{
   
	int mid=(l + r) >> 1;
	if(tree[x]) return ;
	if((l == a) && (r == b)) tree[x]=1;
	else if(b <= mid) insert(2 * x, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值