hdu 4325 Flowers

Flowers

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1988    Accepted Submission(s): 981

Problem Description
As is known to all, the blooming time and duration varies between different kinds of flowers. Now there is a garden planted full of flowers. The gardener wants to know how many flowers will bloom in the garden in a specific time. But there are too many flowers in the garden, so he wants you to help him.
 
Input
The first line contains a single integer t (1 <= t <= 10), the number of test cases.
For each case, the first line contains two integer N and M, where N (1 <= N <= 10^5) is the number of flowers, and M (1 <= M <= 10^5) is the query times. 
In the next N lines, each line contains two integer Si and Ti (1 <= Si <= Ti <= 10^9), means i-th flower will be blooming at time [Si, Ti].
In the next M lines, each line contains an integer Ti, means the time of i-th query.

Output
For each case, output the case number as shown and then print M lines. Each line contains an integer, meaning the number of blooming flowers.
Sample outputs are available for more details.

Sample Input
2
1 1
5 10
4
2 3
1 4
4 8
1
4
6
 
Sample Output
Case #1:
0
Case #2:
1
2

1


这个题有三种解法。线段树+离散化,直接用数组求解,暴力。

第一种线段树+离散化,最复杂的一种方法。这是我做的第一个线段树的题,WA了好多次,才A了。看代码吧

#include "iostream"
#include "cstdio"
#include "algorithm"
using namespace std;

#define lson n<<1
#define rson n<<1|1
#define maxn 100010

struct line{
	int left, right;//左右端点
	int n;//线段出现次数
}tree[maxn<<2];

int st[maxn], ed[maxn];
int q[maxn], data[maxn<<1];

//建立
void Build(int s, int t, int n)
{
	tree[n].left = s;
	tree[n].right = t;
	tree[n].n = 0;
	if(s == t) return;
	int mid = (tree[n].left + tree[n].right)>>1;
	Build(s, mid, lson);
	Build(mid+1, t, rson);
}

void PushDown(int n)
{
	if(tree[n].n > 0)
	{
		tree[lson].n += tree[n].n;
		tree[rson].n += tree[n].n;
		tree[n].n = 0;
	}
}

//插入
void Insert(int s, int t, int n)//要插入线段的左右端点,以及当前线段树中的某条线段
{
	if(s <= tree[n].left && t >= tree[n].right)
	{
		tree[n].n++; //插入线段匹配,次线段出现次数加1
		return;
	}
	else
	{
		PushDown(n);
		if(s <= tree[lson].right)
		{
			Insert(s, t, lson);
		}
		if(t >= tree[rson].left)
			Insert(s, t, rson);
	}
}

//访问
int Query(int index, int n)
{
	if(tree[n].left == tree[n].right) 
		return tree[n].n;
	else
	{
		PushDown(n);
		if(index <= tree[lson].right) 
			return Query(index, lson);
		else
			return Query(index, rson);
	}
}

int main()
{
	int t, ti = 0;
	scanf("%d", &t);
	while(ti < t)
	{
		ti++;
		int n, m, i, cnt = 0;
		scanf("%d %d", &n, &m);
		for(i = 0; i < n; i++)
		{
			scanf("%d %d", &st[i], &ed[i]);
			data[cnt++] = st[i];
			data[cnt++] = ed[i];
		}		
		for(i = 0; i < m; i++)
		{
			scanf("%d", &q[i]);
			data[cnt++] = q[i];
		}
		sort(data, data + cnt);
		cnt = unique(data, data + cnt) - data;
		Build(1, cnt, 1);
		for(i = 0; i < n; i++)
		{
			st[i] = lower_bound(data, data + cnt, st[i]) - data + 1;
			ed[i] = lower_bound(data, data + cnt, ed[i]) - data + 1;
			Insert(st[i], ed[i], 1);
		}
		
		printf("Case #%d:\n", ti);
		for(i = 0; i < m; i++)
		{
			q[i] = lower_bound(data, data + cnt, q[i]) - data + 1;
			printf("%d\n", Query(q[i], 1));
		}
	}
	return 0;
}

第二种方法,直接用数组求解。这是最简单,最巧妙,但也是最不容易想到的方法。看代码

#include "iostream"
#include "cstdio"
#include "algorithm"
using namespace std;

#define maxn 100010

int st[maxn], ed[maxn];

int main()
{
	int t, ti;
	scanf("%d", &t);
	for(ti = 1; ti <= t; ti++)
	{
		int n, m, i;
		scanf("%d %d", &n, &m);
		for(i = 0; i < n; i++)
		{
			scanf("%d %d", &st[i], &ed[i]);
		}
		sort(st, st + n);
		sort(ed, ed + n);
		printf("Case #%d:\n", ti);
		for(i = 0; i < m; i++)
		{
			int q, cnt;
			scanf("%d", &q);
			cnt = upper_bound(st, st + n, q) - st;
			cnt -= lower_bound(ed, ed + n, q) - ed;
			printf("%d\n", cnt);
		}
	}
	return 0;
}

第三种方法,完全暴力,准确说是取巧的方法。感觉用这种方法过的人完全是靠运气。不过运气也是一种能力,不能不服。看代码就知道了。

#include "iostream"
#include "cstdio"
#include "vector"
#include "algorithm"
using namespace std;

int cnt[500005];

int main()
{
    int t, ti = 0;
	scanf("%d", &t);
	while(ti < t)
	{
		ti++;
		memset(cnt, 0, sizeof(cnt));
		int n, m, i;
		scanf("%d %d", &n, &m);
		for(i = 0; i < n; i++)
		{
			int s, t;
			scanf("%d %d", &s, &t);
			int j;
			for(j = s; j <= t; j++)
			{
				cnt[j]++;
			}
		}
		printf("Case #%d:\n", ti);
		for(i = 0; i < m; i++)
		{
			int temp;
			scanf("%d", &temp);
			printf("%d\n", cnt[temp]);
		}
	}
	return 0;
}


 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值