HDU 1828“Picture”(线段树+扫描线求矩形周长并)

 

传送门

 

•参考资料

  [1]:算法总结:【线段树+扫描线】&矩形覆盖求面积/周长问题(HDU 1542/HDU 1828)

•题意

  给你 n 个矩形,求矩形并的周长;

•题解1(两次扫描线)

  周长可以分成两部分计算,横线和竖线;
  如何求解横线的所有并的长度呢?
  和求矩阵面积并的做法一样,先将 x 离散化;
  每次更新的时候,记录一下上次更新后的横线总长度;
  ans += [现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度之差的绝对值];
  求解竖线的所有并的长度何求解横线的长度相同;
  需要注意的是,在求解矩形面积并的时候,排序策略是按照 h 从小到大排序,并不需要考虑 h 相同的情况;
  但是求矩形周长并的时候就不行了,必须得考虑 h 相同的情况下的排序策略;
  以下例求解横线并的长度为例;
    n=2
    (2,1),(4,3)
    (3,3),(4,5)
  定义如下数据结构存储横线;

 1 struct Edge
 2 {
 3     int l,r;
 4     int h;
 5     int f;
 6     bool operator < (const Edge &obj)const
 7     {
 8     return h < obj.h;
 9     }
10 }e[maxn<<1];

  假设与处理矩形面积并的排序策略相同,只考虑按 h 升序排列,那么排列后的数据为:
    $e_{1}:\{l=2\ ,\ r=4\ ,\ h=1\ ,\ f=1 \}$
    $e_{2}:\{l=2\ ,\ r=4\ ,\ h=3\ ,\ f=-1 \}$
    $e_{3}:\{l=3\ ,\ r=4\ ,\ h=3\ ,\ f=1 \}$
    $e_{1}:\{l=3\ ,\ r=4\ ,\ h=5\ ,\ f=-1 \}$
  让我们手动模拟一下这个求解过程;
  定义 ans 表示答案,len 表示当前更新后的横线并的总长度,pre 表示上一次更新后的 len 值;
  初始化 ans=0,len=0,pre=0;
  首先处理 $e_{1}$,update() 后,len = 2;
  更新 ans += |len-pre| = 2 , pre=len=2;
  处理 $e_{2}$,update() 后,len = 0;
  此时,更新 ans += |len-pre| = 2+2 = 4 , pre=len=0,出现问题了是吧,因为来到此处的时候,ans=3才对;
  继续向上更新, $e_{3}$,update() 后,len=1;
  更新 ans += |len-pre| = 4+1 = 5 , pre=len=1;
  $e_{4}$,update() 后,len=0;
  更新 ans += |len-pre| = 5+1 = 6;
  但是正确答案应该是 ans = 4;
  多的 2 就是因为排序策略不当而产生的;
  所以,当 h 相同的时候,应该先处理 f = 1 的边,即如果可以先加入边,那就优先执行加边操作;
  所以,需要将 Edge 中的排序策略更改一下,改成如下模式:

1 bool operator < (const Edge &obj)const
2 {
3     if(h != obj.h)
4         return h < obj.h;
5     return f > obj.f;
6 }    

  (ps:f = 1 表示下边界,所以当 h 相同时,按照 f 降序排列)
  到这,这道题就这么愉快的解决了;

•Code

  HDU1828.cpp

posted @ 2019-09-04 21:51  HHHyacinth  阅读(322)  评论(0编辑  收藏  举报