线段树简单应用 - 区间是否包含

本文介绍了使用线段树进行区间合并及查询的算法实现,包括如何通过cover数组模拟线段树,以及如何通过更新和查询操作处理输入的区间集合,并判断给定区间是否在合并后的区间集合中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    给出n个输入,每个输入都是一个区间,这些区间有可能有重叠,形成区间集合S。现在再给一个区间x,问x是否在S中?

    关键是如何合并区间得到S?可以用线段树做,空间O(N),查询时间为O(lg N)。线段树并不一定需要显式的一个“树”结构,不一定需要定义一个结构体。在这里用一个cover数组来模拟。

    假设输入为:

    1 2
    3 4
    7 9
    11 13

    形成的区间为[1,4],[7,9],[11,13].查询1-13每个点是否在区间中。

#include <iostream>
using namespace std;
const int N = 20;
int cover[N*4] = {0};

// 如果父亲==1,则孩子不需要再等于1,用0表示;如果父亲等于0而孩子都等于1,则令父亲等于1,孩子等于0.
void up(int index)
{
	if (cover[index] == 1)
		cover[index<<1] = cover[(index<<1) + 1] = 0;
	else
		if(cover[index<<1] == 1 && cover[(index<<1) + 1] == 1)
		{
			cover[index] = 1;
			cover[index<<1] = cover[(index<<1) + 1] = 0;
		}
}

// 加入新的区间
void update(int L, int R, int l, int r, int index)
{
	if(L <=l && R >=r)
	{
		cover[index] = 1;
		return;
	}
	int mid = l + (r-l)/2;
	if(L <= mid && cover[index<<1] == 0) // 递归左孩子
		update(L, R, l, mid, index<<1);
	if(R >= mid + 1 && cover[(index<<1) + 1] == 0) // 递归右孩子
		update(L, R, mid+1, r, (index<<1) + 1);
	up(index);
}

int query(int L, int R, int l, int r, int index) // 查询
{
	if (cover[index] == 1) // 如果=1,则说明整个区间都等于1,直接返回1即可
		return 1;
	else
		if (l == r)     // 不等于1,而且已经到叶子节点,则返回0即可
			return 0;
	int mid = l + (r - l)/2;
	int re1 = 1, re2 = 1;
	if (L <= mid)
		re1 = query(L, R, l, mid, index<<1);
	if (R >= mid + 1)
		re2 = query(L, R, mid + 1, r, (index<<1) + 1);
	return re1 && re2;
}

int main()
{
	int x = 4, y = 13;
	int a,b;
	while(x--) // 加入区间
	{
		cin>>a>>b;
		cout<<"输入区间: "<<"["<<a<<","<<b<<"]"<<endl;
		update(a,b,1,20,1);
	}
	int i;
	cout<<"cover 数组"<<endl;
	for(i=1; i<30; i++)
		cout<<cover[i]<<" ";
	cout<<endl;
	while(y--) // 查询
	{
		cin>>a>>b;
		int r = query(a,b,1,20,1);
		cout<<13-y<<" th: "<<"["<<a<<","<<b<<"]  "<<(r?"在区间里":"不在区间里")<<endl;
	}
	return 0;
}
输入文件:

1 2
3 4
7 9
11 13
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
11 11
12 12
13 13


输出:

输入区间: [1,2]
输入区间: [3,4]
输入区间: [7,9]
输入区间: [11,13]
cover 数组
0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 
1 th: [1,1]  在区间里
2 th: [2,2]  在区间里
3 th: [3,3]  在区间里
4 th: [4,4]  在区间里
5 th: [5,5]  不在区间里
6 th: [6,6]  不在区间里
7 th: [7,7]  在区间里
8 th: [8,8]  在区间里
9 th: [9,9]  在区间里
10 th: [10,10]  不在区间里
11 th: [11,11]  在区间里
12 th: [12,12]  在区间里
13 th: [13,13]  在区间里


结果是正确的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值