您的位置:首页 > 其它

Hdu 4325 Flowers 树状数组+离散化

2017-03-22 17:00 183 查看


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 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

题意:不同的花在不同时间段开放,问某个时间段有多少花开着。
思路:看题目我们就知道要把时间作为线段,通过输入的开放时间来更新区间,但是题目给出的时间单位时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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: