zoukankan      html  css  js  c++  java
  • HDU 4509 湫湫系列故事——减肥记II(线段树-区间覆盖 或者 暴力技巧)


    http://acm.hdu.edu.cn/showproblem.php?pid=4509

    题目大意:

      中文意义,应该能懂。

    解题思路:

      因为题目给的时间是一天24小时,而且还有分钟。为了解题方便,我们将小时换成分钟,那么一天24小时,总共有1440分钟。顾我就可以把一天里的任意HH:MM时间换成分钟。就这样一天的时间就变成[0,1440]区间了。

      因为所给的活动最多是5*10^5,如果把活动的时间在线段[0,1440]都修改,那么时间的复杂度最坏是O(5*10^5*1440)。

      (1)方法一:线段树-区间覆盖。

      线段树参考的是《算法入门经典训练指南》刘汝佳 P199

    线段树其中一个特性,区间修改。我们把[0,1440]看成一个区间,我们只需要把活动时间的在线段树中标记就行。因为线段树是区间,每次标记都是区间。所以时间复杂度最坏O(5*10^5*log(1440)),我们只要查询[0,1440]整个区间,统计被覆盖的时间ans,用1440-ans=最后的答案。

      查询时间的复杂度最坏是整棵树的节点O(2*1440)。

      所以总时间复杂度最坏是O(5*10^5*log(1440))+ O(2*1440)。

      注意:线段树的真正区间[1,1440],叶子节点表示是1秒的时间。

      (2)方法二:暴力技巧

      这个方法是借鉴别人的。

    为了好理解这个方法,我们先举个简单的例子。

    我们假设区间是[0,8]。

    输入的数据是:

    3

    1 4

    3 5

    6 7

    求未覆盖的线段和的长度。答案是3。

      具体方法是。当输入1 4时,将1出+1,表示1后面的区间被覆盖了1次,在4出-1,表示4后面的区间取消覆盖1次。 这样就表示了1 4区间被覆盖了。3 5和6 7也是同理。

      怎么求那些区间没有覆盖了,我是从0开始到结束,看每个小区间是否被覆盖。用一个count记录,若count为零时,表示此节点没有被覆盖。

      区间修改的时间复杂度是O(5*10^5*1),区间查询是整个区间时间复杂度是O(1440)

    顾总时间复杂度是O(5*10^5*1)+O(1440)

    AC代码:

    线段树

     1 #include<cstdio>
     2 #include<cstring>
     3 
     4 #define MAXN 1441//时间最多是1440
     5 
     6 bool stree[MAXN << 2];//线段树
     7 
     8 int L, R;//要覆盖的区间为[L,R]
     9 void updata(int o, int lc, int rc){//区间覆盖
    10     if(stree[o]) return ;//此区间被覆盖了
    11     if(L <= lc && rc <= R){//区间[lc,rc]在被覆盖的范围
    12         stree[o] = true;
    13         return ;
    14     }
    15     int mid = (lc + rc) >> 1;
    16     if(L <= mid) updata(o * 2 + 1, lc, mid);
    17     if(mid < R) updata(o * 2 + 2, mid + 1, rc);
    18 }
    19 
    20 int ans;//统计被覆盖的时间和
    21 void query(int o, int lc, int rc){
    22     if(stree[o]){
    23         ans += rc - lc + 1;
    24         return ;
    25     }
    26 
    27     if(lc == rc) return ;//访问到叶子节点了
    28 
    29     int mid = (lc + rc) >> 1;
    30     query(o * 2 + 1, lc, mid);
    31     query(o * 2 + 2, mid + 1, rc);
    32 }
    33 
    34 int main(){
    35     int n, hh[2], mm[2];
    36     while(~scanf("%d", &n)){
    37 
    38         memset(stree, 0, sizeof(stree));
    39         while(n--){
    40             scanf("%d:%d %d:%d", &hh[0], &mm[0], &hh[1], &mm[1]);
    41             mm[0] += hh[0] * 60 + 1;
    42             mm[1] += hh[1] * 60;
    43             L = mm[0]; R = mm[1];
    44             updata(0, 1, 1440);//区间修改
    45         }
    46         ans = 0;
    47         query(0, 1, 1440);//区间访问
    48         printf("%d
    ", 1440 - ans);
    49     }
    50     return 0;
    51 }


    暴力技巧:

     1 #include<cstdio>
     2 #include<cstring>
     3 
     4 #define MAXN 1441
     5 
     6 int time[MAXN];
     7 
     8 int main(){
     9     int n, hh[2], mm[2];
    10     while(~scanf("%d", &n)){
    11 
    12         memset(time, 0, sizeof(time));
    13         while(n--){
    14             scanf("%d:%d %d:%d", &hh[0], &mm[0], &hh[1], &mm[1]);
    15             mm[0] += hh[0] * 60;
    16             mm[1] += hh[1] * 60;
    17 
    18             ++time[mm[0]]; --time[mm[1]];
    19         }
    20 
    21         int ans = 0, count = 0;
    22         for(int i = 0; i < 1440; ++i){
    23             count += time[i];
    24             if(count == 0) ++ans;
    25         }
    26         printf("%d
    ", ans);
    27     }
    28     return 0;
    29 }
  • 相关阅读:
    算法训练 区间k大数查询
    算法训练 最大最小公倍数
    身份证号码升级
    python包与模块导入
    python函数
    HDU 3595 博弈论,被支配的恐惧
    BZOJ 3195 [Jxoi2012]奇怪的道路
    大暑假集训
    [Poi2010]Monotonicity 2
    BZOJ 4868 HEOI 期末考试
  • 原文地址:https://www.cnblogs.com/xuqiulin/p/4038928.html
Copyright © 2011-2022 走看看