线段树练习题二

Time Limit:10000MS Memory Limit:65536K
Total Submit:154 Accepted:85
Case Time Limit:1000MS


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


Input

Output


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<=100000,1<=m<=100000 1<=n<=100000,1<=m<=100000,保证坐标范围为 [ 1 , n ] [1,n] [1,n]


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


代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,l,ans,x,y,c[400010],f[400010];
void insert(int dep,int l,int r,int x,int y,int color)
{
	
	if(c[dep]!=color) 
	{
		int mid=(l+r)/2;
		if(l==x&&r==y)
		{
			c[dep]=color;
			return;
		} 
		if(c[dep]>0)
		{
			c[2*dep]=c[2*dep+1]=c[dep];
			c[dep]=-1;
		}
		if(y<=mid) insert(2*dep,l,mid,x,y,color);
		else if(x>=mid) insert(2*dep+1,mid,r,x,y,color);
		else 
		{
			insert(2*dep,l,mid,x,mid,color);
			insert(2*dep+1,mid,r,mid,y,color);
		}
	}
}
void ccount(int dep,int l,int r){
	int mid=(l+r)/2;
	if(c[dep]>0)
	{
		f[c[dep]]=1;
		return;
	}
	if(r-l>1)
	{
		ccount(2*dep,l,mid);
		ccount(2*dep+1,mid,r);
	} 
}
int main(){
	scanf("%d%d",&l,&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		insert(1,1,l,x,y,i);
	}
	ccount(1,1,l);
	for(int i=1;i<=n;i++)
		if(f[i]) 
		ans++;//使用一个数组F,初始化为0。遍历线段树,对于每种颜色c对F[c]赋值1。最后统计F中1的个数即可。
	printf("%d",ans);
}

你可能感兴趣的:(线段树)