nyist 600 - 花儿朵朵

题目:给定很多花的开花时间段,询问某一时间点有多少朵花儿开放。

分析:线段树、离散化。利通每朵花的开花时间段的端点值将时间轴分割成区间段,则操作以每个区间段为整体进行。分割又两种方案:1.端点各成一段,端点间各成一段;2.建立左闭右开的区间,每个区间从上一个顶点开始、到下一个顶点之前结束(开区间)。本题采用方案2,方案一需要生成4倍花儿的数量,而方案2只需要2倍花儿的数量,空间复杂度会降低一倍。注意,在每个叶子节点上建立节点[a,a],因为操作[a,b]区间需要操作[a,b)和[b,b]两个区间,所以线段树的结点数是区间的3倍(2n-1+n),而不是通常的2倍(2n-1)。

注意:在线段树的建树过程中不要使用memset,会TLE。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int x[100005];
int y[100005];
int z[200005];
int s[200005];

typedef struct Tnode
{
	Tnode*  Lchild;
	Tnode*  Rchild;
	int     Lvalue;
	int	Rvalue;
	int     Counts;
}STnode;
STnode Node[600005];

class Stree
{
private:
	STnode* Root;
	int 	Count;
	STnode* madetree( int a, int b ) {
		STnode* np = &Node[Count++];
		np->Counts = 0;
		np->Lvalue = a;
		np->Rvalue = b;
		if ( a < b ) {
			np->Lchild = madetree( a, (a+b)/2 );
			if ( a+1 < b )
				np->Rchild = madetree( (a+b)/2, b );
		}else np->Lchild = np->Rchild = NULL;
		return np;
	}
public:
	Stree( int a, int b ) {
		Count = 0;
		Root  = madetree( a, b );
	}
	void Insert( STnode* r, int a, int b ) {
		//printf("[%d %d] <%d %d>\n",r->Lvalue,r->Rvalue,a,b);
		if ( r->Lvalue == a && r->Rvalue == b ) {
			r->Counts ++;
			return;
		}
		int mid = (r->Lvalue+r->Rvalue)>>1;
		if ( b < mid || a == b ) {
			if ( r->Lchild ) Insert( r->Lchild, a, b );
		}else if ( a >= mid ) {
			if ( r->Rchild ) Insert( r->Rchild, a, b );
		}else {
			if ( r->Lchild ) Insert( r->Lchild, a, mid );
			if ( r->Rchild ) Insert( r->Rchild, mid, b );
		}
	}
	int  Query( STnode* r, int v ) {
		if ( !r ) return 0;
		//printf("{%d %d}\n",r->Lvalue,r->Rvalue);
		if ( r->Lvalue == r->Rvalue )
			return s[r->Lvalue]==v?r->Counts:0;
		if ( v < s[r->Lvalue] || v >= s[r->Rvalue] )
			return 0;
		int mid = (r->Lvalue+r->Rvalue)>>1;
		if ( v < s[mid] || r->Lvalue+1 == r->Rvalue )
			return Query( r->Lchild, v )+r->Counts;
		else 
			return Query( r->Rchild, v )+r->Counts;
	}
	void Insert( int a, int b ) {Insert( Root, a, b );}
	int  Query( int v ) {Query( Root, v );}
};

int Map( int numb, int m )
{
	int l = 1,r = m,mid;
	while ( l < r ) {
		mid = (l+r)>>1;
		if ( s[mid] < numb ) 
			l = mid+1;
		else r = mid;
	}
	return r;
}

int cmp( const void* a, const void* b )
{
	return *((int *)a) - *((int*)b);
}

int main()
{
	int n,m,t,a,b,ans;
	while ( scanf("%d",&t) != EOF )  
	while ( t -- ) {
		scanf("%d%d",&n,&m);
		for ( int i = 0 ; i < n ; ++ i ) {
			scanf("%d%d",&x[i],&y[i]);
			z[i] = x[i];z[i+n] = y[i];
		}
		qsort( z, 2*n, sizeof( int ), cmp );
		
		int count = 0;
		s[++count] = z[0];
		for ( int i = 1 ; i < 2*n ; ++ i )
			if ( z[i-1] != z[i] )
				s[++count] = z[i];
		s[++count] = s[count-1]+1;

		Stree ST( 1, count );
		for ( int i = 0 ; i < n ; ++ i ) {
			a = Map( x[i], count );
			b = Map( y[i], count );
			ST.Insert( a, b );
		}
		
		for ( int i = 0 ; i < m; ++ i ) {
			scanf("%d",&ans);
			printf("%d\n",ST.Query( ans ));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值