• 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 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
     
    题意:有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 }
  • 相关阅读:
    找轮转后的有序数组中第K小的数
    linux下安装tomcat,并设置自动启动
    maven中添加proguard来混淆代码
    Maven编译可执行jar
    Maven pom项目部署
    Eclipse主题设置
    double hashing 双重哈希
    推荐系统
    vim插件
    多标记学习--Learning from Multi-Label Data
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/9886070.html
Copyright © 2020-2023  润新知