【ssl2645】【线段树练习题2】【线段树变式】

Description

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

Sample Input

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

Sample Output

4

Hint

1<=n<=100000,1<=m<=100000,保证坐标范围为[1,n].

分析

可以这样来看这道题:x轴上有若干条不同线段,将它们依次染上不同的颜色,问最后能看到多少种不同的颜色?(后染的颜色会覆盖原先的颜色)
我们可以这样规定:x轴初始是颜色0,第一条线段染颜色1,第二条线段染颜色2,以此类推。
原先构造线段树的方法不再适用,但是我们可以通过修改线段树的cover域的定义,使得这道题也能用线段树来解。
定义cover如下:cover=−1表示该区间由多种颜色组成。cover>=0表示该区间只有一种单一的颜色cover.

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
int n,m,l,r,ans,f[100001],tree[300001];
void insert(int k,int l,int r,int x,int y,int c)
{
	if(tree[k]!=c)
	{
		int mid=(l+r)/2;
		if(l==x&&r==y)
		{
			tree[k]=c;
		}
		else
		{
			if(tree[k]>=0)
			{
				tree[k*2]=tree[k*2+1]=tree[k];
				tree[k]=-1;
			}
			if(y<=mid)
			{
				insert(k*2,l,mid,x,y,c);
			}
			else if(x>=mid) 
			{
				insert(k*2+1,mid,r,x,y,c);
			}
			else
			{
				insert(k*2,l,mid,x,mid,c);
				insert(k*2+1,mid,r,mid,y,c);
			}
		}
	}
}
void cnt(int k,int l,int r)
{
	int mid=(l+r)/2;
	if(tree[k]>=0)
	{
		f[tree[k]]=1;
	}
	else if(l+1<r)
	{
		cnt(k*2,l,mid);
		cnt(k*2+1,mid,r);
	}
} 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>l>>r;
		insert(1,1,n,l,r,i);
	}
	cnt(1,1,n);
	for(int i=1;i<=m;i++)
	{
		if(f[i]!=0)
		{
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值