Hdu 4325 Flowers 树状数组+离散化

Flowers

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 65536/65536K (Java/Other)
Total Submission(s) : 2   Accepted Submission(s) : 2
Font: Times New Roman | Verdana | Georgia
Font Size:  

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 S i and T i (1 <= S i <= T i <= 10^9), means i-th flower will be blooming at time [S i, T i].
In the next M lines, each line contains an integer T i, 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
题意:不同的花在不同时间段开放,问某个时间段有多少花开着。
思路:看题目我们就知道要把时间作为线段,通过输入的开放时间来更新区间,但是题目给出的时间单位时1~1^9,数组开不了那么大,所以得用离散化来解决这个问题。 离散化:(把很大的时间区间用比较小的值来保存,比如 100 25 300 40 ,就可以分别保存为3 1 4 2。这样就可以节省空间了,由于题目给的n时50000,所以时间最多最多只能分这么多区间,所以数组开500000就可以了。
把时间分区间的方法:首先每个点用结构体存,存它是第几朵花和它的时间点,然后先按时间从小到大排,然后给它一个id,用来时间分区,并且同时把你后面输入的查询时间也用相同的方法保存。然后用树状数组把点按花朵编号的顺序存进去,但给的时间是离散化后的时间,最后给出答案就好了。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 500000
int sum1[maxn],sum2[maxn],id;
struct Node{		//点的结构体 
	int num,pos;
}node[maxn];
int cmp(const Node &a,const Node &b){
	return a.num < b.num;		//升序排列 
}
int getSum(int x){		// 统计区间数值 
	int sum = 0;
	while(x > 0){	
		sum += sum1[x];
		x -= x & -x;
	}
	return sum;
}
void update(int pos,int num){		// 把sum2里的数,就是时间点扔进来,把这个时间点之后的区间更新 
	while(pos <= id){	
		sum1[pos] += num;
		pos += pos & -pos;
	}
}
int main(){
	int n,m,t,Case = 1;
	scanf("%d",&t);
	while(t--){
		printf("Case #%d:\n",Case++);
		scanf("%d %d",&n,&m);
		int tn = n * 2;
		int tm = tn + m;
		for(int i = 0;i < tm;i++){
			scanf("%d",&node[i].num);
			node[i].pos = i;
		}
		sort(node,node + tm,cmp);	//把所有输入进来的时间点按从小到大排序,然后分成小区间存sum2里 
		id = 1;
		sum2[node[0].pos] = id;		//第一个点就存1 
		for(int i = 1;i < tm;i++){			//把数离散化分成小的存在sum2里面 
			if(node[i].num == node[i - 1].num){ //若这个点与前一个点时间相同,则存同一个区间 
				sum2[node[i].pos] = id;
			}else{								//不相同则存下一个区间 
				sum2[node[i].pos] = ++id;
			}
		}
		memset(sum1,0,sizeof(sum1));  
		for(int i = 0;i < tn - 1;i++){
			update(sum2[i++],1);	//把前数扔进来,后面区间加一 
			update(sum2[i] + 1, -1);	//后数扔进来,后面巨剑减一 
		}
		for(int i = tn;i < tm;i++){
			printf("%d\n",getSum(sum2[i])); //sum2[i]指的时那个时间点的离散化后的时间点,找到这个时间点里存的值。 
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值