hdu4325-Flowers-树状数组+离散化

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 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
 
题意: 有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:\n",++cnt);
92         for(int i=0; i<m; ++i)
93         {
94             cout<<query( bSerach(ques[i], cnt2) )<<endl; //树状数组单点查询 
95         }
96     }
97     return 0;
98 }

猜你喜欢

转载自www.cnblogs.com/tuyang1129/p/9886070.html