【线段树】线段树练习题二

这篇博客介绍了一道使用线段树解决的实际问题:如何计算在一定视角下能看到的桌子上的盒子数量。通过给出Input和Output的示例,解释了线段树在这类问题中的应用,即使不进行初始化也能实现高效求解。

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

桌子上零散地放着若干个不同颜色的盒子,桌子的后方是一堵墙。如右图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远(输入时,由底向上,从左到右)。

Input

第一行,一个数m代表桌子长度
第二行,一个数n代表盒子数量
第3到n+2行,每行两个数,代表盒子的宽度

Output

一个数,可以看到的盒子数。

Sample Input
16  //桌子长度
5   // 盒子数量
4 7
12 14
1 5
6 10
11 16
Sample Output
4

线段树(这里懒得初始化建线段树什么的,居然跑得快了一点)

#include<cstdio>

int Color[400001],B[100001];   //Color存某节点的颜色状态,-1表示这一段有颜色,但不全覆盖
                               //B存某颜色是否出现。
int n,m,color,ans,q,z;

void add(int d,int Left,int Right, int l, int r){  //在d点,即Left到Right的范围内寻找l到r
	if(Left == l && Right == r){  //如果找到
		Color[d] = color;
		return;
	}
	if(Color[d] >= 0){   //如果有颜色经过这
		Color[d << 1] = Color[d];   //下传
		Color[(d << 1)+1] = Color[d];
		Color[d] = -1;  //置为这一段中有颜色,但不是覆盖整一段
	}
	int mid = (Left + Right) >> 1;   //二分
	if(r <= mid) add(d << 1, Left, mid, l, r);   //如果都在左子节点那边
	else if(l >= mid) add((d << 1) + 1, mid, Right, l, r);   //如果在右子节点那边
	else{
		add(d << 1, Left, mid, l, mid);   //两边都有一部分
		add((d << 1) + 1, mid, Right, mid, r);
	}  
}

void find(int d){   //寻找d以及它后面的子节点有多少个颜色
	if(Color[d] == -1){   //如果这个节点它下面有颜色
		find(d << 1);    //搜
		find((d << 1) + 1); 
	}
	else if(B[Color[d]] == 0 && Color[d] != 0){  //如果这一段被完全覆盖,且颜色未被记录,且颜色不等于0
		B[Color[d]] = 1; 
		++ans;   //答案数+1
	}
}

int read(){     //快读
	int d=0;char c;
	c=getchar();
	while(c>'9'||c<'0') c=getchar();
	while(c<='9'&&c>='0') {
		d=d*10+c-48;
		c=getchar();
	}
	return d; 
}

int main(){
	m=read();  //读入
	n=read();
	for(int i = 1; i <= n; ++i, ++color){
		q=read();
		z=read();
		add(1, 1, m, q, z);  //处理
	}
	find(1);    //寻找
	printf("%d",ans);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值