zoukankan      html  css  js  c++  java
  • hicocoder1079离散化+线段树

    题目链接:http://hihocoder.com/problemset/problem/1079

    题目大意:

      有一条数轴,先后对数轴上的一些区间着上不同的颜色,后着色的区间若跟先着色的区间有重合,则重合部分颜色将被后着色的区间颜色覆盖,求在一系列的区间着色操作之后,最终数轴上的颜色有几种。区间数目n<=10^5, 区间长度最大值L<=10^9.

    这道题目乍看上去就是一道简单的线段树区间更新区间查询的问题,但仔细一看发现,区间长度最大值L可能达到10^9,若按照普通的线段树来做,内存根本开不下。

      这时候我们注意到:假设现在有两个区间要着色,并求最后颜色有几种,我们对区间[0, 100000000]和[2, 1000000001]着色其实与对区间[0, 2]和[1, 3]着色对我们的答案并没有任何影响,因为将区间[0, 100000000]和[2, 1000000001]改为[0, 2]和[1, 3]并没有改变区间端点之间的相对大小。

      所以,离散化要做的就是,先将所有的2*n个区间端点记录下来,并将每个端点值映射到另外一个值上,只要不改变其相对大小关系,若我们的映射值从0开始逐1增加,那么最后得到的所有映射值的最大值不会超过2*n个。这样映射以后,再用线段树来做,就不存在内存开不下的问题了。

      另外需要注意的是:这里的线段树区间是连续的,与区间离散的线段树最明显的不同是,前者左右儿子表示的区间为[l, m]、[m+1, r]这种形式而后者表示的区间为[l, m]、 [m, r]这种形式,前者的叶子节点表示的区间为[i, i]这种形式而后者的叶节点表示的区间为[i, i+1]这种形式。

    我的代码:

     1 #include <iostream>
     2 #include <set>
     3 #include <map>
     4 
     5 using namespace std;
     6 
     7 #define MAXN 2*100005
     8 
     9 int ll[MAXN/2], rr[MAXN/2];
    10 set<int> st;
    11 map<int, int> mp;
    12 
    13 struct segNode
    14 {
    15     int left, right, id;
    16     bool lazy;
    17 };
    18 
    19 struct segTree
    20 {
    21     segNode t[4*MAXN];
    22     void build(int i, int l, int r)
    23     {
    24         t[i].left = l;
    25         t[i].right = r;
    26         t[i].lazy = false;
    27         if(l+1<r)
    28         {
    29             int m = (l+r)/2;
    30             build(2*i, l, m);
    31             build(2*i+1, m, r);
    32         }
    33     }
    34     void pushdown(int i)
    35     {
    36         t[i].lazy = false;
    37         t[2*i].id = t[i].id;
    38         t[2*i+1].id = t[i].id;
    39         t[2*i].lazy = true;
    40         t[2*i+1].lazy = true;
    41     }
    42     void update(int i, int l, int r, int v)
    43     {
    44         if(t[i].left+1<t[i].right&&t[i].lazy)  pushdown(i);
    45         if(t[i].left==l&&t[i].right==r)
    46         {
    47             t[i].id = v;
    48             t[i].lazy = true;
    49         }
    50         else
    51         {
    52             int m = (t[i].left+t[i].right)/2;
    53             if(r<=m)    update(2*i, l, r, v);
    54             else if(l>=m)   update(2*i+1, l, r, v);
    55             else
    56             {
    57                 update(2*i, l, m, v);
    58                 update(2*i+1, m, r, v);
    59             }
    60         }
    61     }
    62     void query(int i)
    63     {
    64         if(t[i].lazy) st.insert(t[i].id);
    65         else if(t[i].left+1<t[i].right)
    66         {
    67             query(2*i);
    68             query(2*i+1);
    69         }
    70     }
    71 }tree;
    72 
    73 int main()
    74 {
    75     int n, l;
    76     while(cin>>n>>l)
    77     {
    78         st.clear();
    79         mp.clear();
    80         for(int i=0; i<n; ++i)
    81         {
    82             cin>>ll[i]>>rr[i];
    83             st.insert(ll[i]);
    84             st.insert(rr[i]);
    85         }
    86         int cnt = 0;
    87         for(set<int>::iterator it=st.begin(); it!=st.end(); it++)   mp[*it] = cnt++;
    88         st.clear();
    89         tree.build(1, 0, cnt-1);
    90         for(int i=0; i<n; ++i) tree.update(1, mp[ll[i]], mp[rr[i]], i);
    91         tree.query(1);
    92         cout<<st.size()<<endl;
    93     }
    94     return 0;
    95 }
  • 相关阅读:
    MFC STATIC,Picture控件使用及无法添加变量的问题
    MFC listctrl NMCLICK消息 错误 无法从"NMHDR*"转换为"NMITEMACTIVATE"
    vs2008中将开始执行按钮(不调试按钮)添加至标准工具栏方法
    MFC 删除工具栏 默认对话框全屏 修改MFC标题栏的文字 删除菜单栏
    Visual Assist X设置
    MFC禁止窗口最大化按钮和禁止改变窗口大小
    MFC从头开始如何利用MFC分割窗口
    MFC CSplitterWnd窗口分割
    关于VS2008下提示microsoft incremental linker已停止工作的问题
    windows 下codeblocks查看容器值
  • 原文地址:https://www.cnblogs.com/pczhou/p/4297511.html
Copyright © 2011-2022 走看看