Flowers
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3687 Accepted Submission(s): 1821
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.
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 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
题意:有n朵花,每一朵花只会在固定的时间范围内绽放,m次询问,让你求在某个时刻有多少朵花是绽放的。
思路:这题可以看成是树状数组的区间更新,给出每一朵花开放的时间范围,就相当于做一次区间更新,这个范围内的每个点加1,直接使用树状数组区间跟新的模板就好了。
可是这题有个问题,那就是花开放范围的数据极大(1-10^9),无法直接开数组储存每一个点。那怎么办呢,很明显需要用到数据的离散化。
我们可以发现,虽然花开放范围极大,但是总共只有n朵花,n最大是10^5,每一个范围由两个数l,r组成,再加上最多10^5个查询数,也就意味着一组数据最多出现3*(10^5)个不同的数据,数组完全能够存下。而且我们判断花是否在某一时刻开放,只需要知道数与数之间的相对大小,而不需要在意具体数值(某一时刻在 l , r之间,即花是开的),所以,这就满足了离散化的条件。
我们对每一朵花开放的范围进行离散化,也对查询的时刻进行离散化,这样,就不会改变他们的相对大小。然后使用树状数组区间更新+单点查询即可。
离散化的方法:将所有出现的数存入数组,去除重复出现的数,再进行排序,排序后这个数在数组中对应的下标,即为其离散化之后的数值。
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 #include<stack> 8 #include<climits> 9 #include<map> 10 #include<queue> 11 #define eps 1e-7 12 #define ll long long 13 #define inf 0x3f3f3f3f 14 #define pi 3.141592653589793238462643383279 15 using namespace std; 16 const int MAXN = 3e5 + 21; 17 18 int getNum[MAXN],li[MAXN/3],ri[MAXN/3],c[MAXN]; 19 20 int lowBit(int x) 21 { 22 return x&(-x); 23 } 24 25 void add(int x,int num,int len) //区间更新 26 { 27 for(int i=x; i<=len; i+=lowBit(i)) 28 { 29 c[i] += num; 30 } 31 } 32 33 ll query(int x) //单点查询 34 { 35 ll ans = 0; 36 for(int i=x; i>0; i-=lowBit(i)) 37 { 38 ans += c[i]; 39 } 40 return ans; 41 } 42 43 int bSerach(int num,int len) //找出某个数在数组中的下标,并返回下标+1 44 { 45 return lower_bound(getNum,getNum+len,num) - getNum + 1; 46 } 47 48 int main() 49 { 50 int t,n,m,cnt = 0; 51 cin>>t; 52 while(t--) 53 { 54 memset(c,0,sizeof(c)); 55 memset(getNum,0,sizeof(getNum)); 56 57 scanf("%d%d",&n,&m); 58 59 int cnt1 = 0; 60 61 for(int i=0; i<n; ++i) 62 { 63 scanf("%d%d",&li[i],&ri[i]); 64 getNum[cnt1++] = li[i]; //将花开放范围出现的数据存入数组 65 getNum[cnt1++] = ri[i]; 66 } 67 68 int ques[MAXN/3]; 69 for(int i=0; i<m; ++i) 70 { 71 scanf("%d",&ques[i]); 72 getNum[cnt1++] = ques[i]; //将查询出现的数据存入数组 73 } 74 75 sort(getNum,getNum+cnt1); //给所有出现的数排序 76 77 int cnt2 = 1; 78 for(int i=1; i<cnt1; ++i) 79 { 80 if(getNum[i] != getNum[i-1]) //去除重复的数 81 getNum[cnt2++] = getNum[i]; 82 } 83 84 85 for(int i=0; i<n; ++i) //树状数组区间更新 86 { 87 add( bSerach(li[i],cnt2), 1,cnt2); 88 add( bSerach(ri[i],cnt2)+1, -1,cnt2); 89 } 90 91 printf("Case #%d: ",++cnt); 92 for(int i=0; i<m; ++i) 93 { 94 cout<<query( bSerach(ques[i], cnt2) )<<endl; //树状数组单点查询 95 } 96 } 97 return 0; 98 }