zoukankan      html  css  js  c++  java
  • POJ 2528 Mayor's posters 线段树+离散化

    题目:http://poj.org/problem?id=2528

    很经典的题目,线段树入门题,写了好几天终于懂离散化了。

    题意是在一个被分成 10000000 段的墙上贴海报,从L贴到R,问最后能看见几张海报。

    因为海报只能是后来的覆盖先来的,所以逆序贴,每贴一张就标记它表示的线段,这样当贴到第i张时,如果表示的线段都被标记过了,说明这张不会被看到。注意离散化时如果相邻两点相差 > 1,要插入额外点,表示之间有间隔,更多细节在注释中。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <algorithm>
      4 
      5 const int MAXN = 20010;
      6 
      7 int dic[MAXN<<1];
      8 bool isview;
      9 
     10 //每张海报表示的线段
     11 struct Segment
     12 {
     13     int left;
     14     int right;
     15     int num;
     16 } seg[MAXN];
     17 
     18 struct Tree_Node
     19 {
     20     int left;
     21     int right;
     22     bool flag; //有没有被覆盖
     23 } tree[MAXN<<3];
     24 
     25 void build(int left, int right, int step)
     26 {
     27     tree[step].left = left;
     28     tree[step].right = right;
     29     tree[step].flag = 0;
     30     if(left == right)
     31         return;
     32     int mid = (left + right) >> 1;
     33     build(left, mid, step<<1);
     34     build(mid+1, right, step<<1|1);
     35 }
     36 
     37 void insert(int left, int right, int step)
     38 {
     39     int mid = (tree[step].left + tree[step].right) >> 1;
     40     if(tree[step].left == left && tree[step].right == right)
     41     {
     42         if(!tree[step].flag)
     43         {
     44             //如果没有被覆盖,标记isview为真
     45             isview = 1;
     46             
     47             //同时标记子节点
     48             if(tree[step].left != tree[step].right)
     49             {
     50                 insert(left, mid, step<<1);
     51                 insert(mid+1, right, step<<1|1);
     52             }
     53         }
     54         tree[step].flag = 1;
     55         return;
     56     }
     57     if(tree[step].left == tree[step].right)
     58         return;
     59     if(mid >= right)
     60     {
     61         insert(left, right, step<<1);
     62     }
     63     else if(mid < left)
     64     {
     65         insert(left, right, step<<1|1);
     66     }
     67     else
     68     {
     69         insert(left, mid, step<<1);
     70         insert(mid+1, right, step<<1|1);
     71     }
     72     
     73     //这里是重点,如果两个子结点都被标记了,则标记当前父节点
     74     if(tree[step<<1].flag && tree[step<<1|1].flag)
     75     {
     76         tree[step].flag = 1;
     77     }
     78 }
     79 
     80 int search(int low, int high, int key)
     81 {
     82     while(low <= high)
     83     {
     84         int mid = (low + high) >> 1;
     85         if(dic[mid] < key)
     86             low = mid + 1;
     87         else if(dic[mid] > key)
     88             high = mid - 1;
     89         else
     90             return mid;
     91     }
     92 }
     93 
     94 int cmp(const struct Segment &x, const struct Segment &y)
     95 {
     96     return x.num > y.num;
     97 }
     98 
     99 int main()
    100 {
    101     int t, n;
    102     int tmp[MAXN];
    103     scanf("%d", &t);
    104     while(t--)
    105     {
    106         scanf("%d", &n);
    107         for(int i = 0; i < n; i++)
    108         {
    109             scanf("%d %d", &seg[i].left, &seg[i].right);
    110             seg[i].num = i;
    111             tmp[i<<1] = seg[i].left;
    112             tmp[i<<1|1] = seg[i].right;
    113         }
    114         
    115         //离散化
    116         std::sort(tmp, tmp + (n<<1));
    117         int sum = 0;
    118         dic[0] = tmp[0];
    119         for(int i = 1; i < (n<<1); i++)
    120         {
    121             if(tmp[i] != dic[sum])
    122             {
    123                 //加额外线段
    124                 if(tmp[i] - dic[sum] > 1)
    125                     dic[++sum] = tmp[i] - 1;
    126                 dic[++sum] = tmp[i];
    127             }
    128         }
    129 
    130         int ans = 0;
    131         build(0, sum, 1);
    132         //按张贴前后逆序排序
    133         std::sort(seg, seg+n, cmp);
    134         for(int i = 0; i < n; i++)
    135         {
    136             int left = search(0, sum, seg[i].left);
    137             int right = search(0, sum, seg[i].right);
    138             //假设当前线段不能看到(即被完全覆盖)
    139             isview = 0;
    140             insert(left, right, 1);
    141             if(isview)ans++;
    142         }
    143         printf("%d
    ", ans);
    144     }
    145     return 0;
    146 }
    View Code
  • 相关阅读:
    批量改文件名小工具
    整理一下在 npmjs.com 上面发布资源包踩过的坑
    告别Vuex,发挥compositionAPI的优势,打造Vue3专用的轻量级状态
    vue3 专用 indexedDB 封装库,基于Promise告别回调地狱
    C++ 学习笔记(三):介绍几个在线编译器【转】
    【Linux】一篇文章彻底搞定信号!【转】
    缓存淘汰算法系列(一)【转】
    缓存淘汰算法 LRU 和 LFU【转】
    NAND Flash标准之ONFI VS TOGGLE【转】
    NAND FLASH学习笔记之nand flash基础(一)【转】
  • 原文地址:https://www.cnblogs.com/wolfred7464/p/3405498.html
Copyright © 2011-2022 走看看