HDU - 1542 扫描线入门+线段树离散化

扫描线算法+线段树维护简介:

像这种求面积的并集的题目,就适合用扫描线算法解决,具体来说就是这样

类似这种给出点的矩形的对角的点的坐标,然后求出所有矩形面积的交集的问题,可以采用扫描线算法解决。图如下,我们要求红色部分的面积:

我们可以通过一条叫扫描线的东西解决问题。具体来说:

我们首先给自己一条线,这条可以我称之为标准线(棕色线表示)

从上往下(从下往上也行)我们把每个矩形用一个四元组表示了l,r,h,f  也就是说,把一个矩形用上下两条边表示,l,r分别是x1,x2,而h则是y坐标,f代表这条线是顶边还是低边。

这样就把信息存储下来。

需要注意的一点是,由于线段树维护区间的时候,会存在区间过大的清空,因此我们需要对x坐标进行去重排序,从而达到把点进行离散化,但是这里我们需要注意的是,我们这里维护区间,而线段树是从维护点,进而维护区间的,因此我们可以这样,把区间的左下标表示为区间,比如[0-3]区间,我们可以转化为点0,代表0-1,1代表1-2,2代表2-3。这样我们再找左端点的时候,我们之间用坐标代替,而右端点,则需要查找到下标后,减一即可。

维护总的区间的和,用高度差乘以区间和,就是面积,每次维护,求出面积,就是如上图所示的样子,从下往上不断求出面积。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
inline int L(int r){return r<<1;};
inline int R(int r){return r<<1|1;};
inline int MID(int l,int r){return (l+r)>>1;};
const int maxx = 111;
struct segment{
  double l,r,h;
  int f;
}ss[maxx*2];
struct node{
  int l,r,cnt;
  double len;
}tree[maxx<<3];
double pos[maxx*2];
int nums;
bool cmp(segment p,segment q)
{
    return p.h<q.h;
}
void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].cnt=0;
    tree[root].len=0;
    if (l==r)
        return;
    int mid = MID(tree[root].l,tree[root].r);
    build(L(root),l,mid);
    build(R(root),mid+1,r);
}
void get_len(int root)
{
    if (tree[root].cnt)//不是0 代表已经被整段覆盖
        tree[root].len = pos[tree[root].r+1] - pos[tree[root].l];
    else if (tree[root].l == tree[root].r)//只是一个点
        tree[root].len = 0;
    else
        tree[root].len = tree[L(root)].len + tree[R(root)].len;
}
void update(int root,int l,int r,int val)
{
    if (tree[root].l == l && tree[root].r == r)
    {
        tree[root].cnt += val;
        get_len(root);
        return;
    }
    int mid = (tree[root].l + tree[root].r)>>1;
    if (r<=mid)
       update(L(root),l,r,val);
    else if (l > mid)
        update(R(root),l,r,val);
    else {
        update(L(root),l,mid,val);
        update(R(root),mid+1,r,val);
    }
   get_len(root);
}
int binary(double key,int low,int high)
{
   // cout<<key<<endl;
    int mid;
     while(low<=high)
     {
         mid = MID(low,high);
         if (pos[mid]==key)
             return mid;
         else if (key < pos[mid])
            high = mid-1;
         else
            low = mid+1;
     }
     return -1;
}
int main(){
  int Case = 0;
  int n;
  while(scanf("%d",&n)!=EOF && n)
  {
      nums=0;
      for (int i=0;i<n;i++){
        double x1,y1,x2,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        //记录下边
        ss[nums].l = x1;
        ss[nums].r = x2;
        ss[nums].h = y1;
        ss[nums].f = 1;
        //记录上边
        ss[nums+1].l = x1;
        ss[nums+1].r = x2;
        ss[nums+1].h = y2;
        ss[nums+1].f = -1;
        //记录横坐标
        pos[nums] = x1;
        pos[nums+1] = x2;
        nums+=2;
      }
      sort(ss,ss+nums,cmp);
      sort(pos,pos+nums);
      int m = 1;
      for (int i=1;i<nums;i++)//离散去重
        if (pos[i]!=pos[i-1])
          pos[m++]=pos[i];
      memset(tree,0,sizeof(tree));
      build(1,0,m-1);//离散区间就是[0,m-1]
//      for (int i=0;i<=m*4+2;i++){
//        cout<<tree[i].l<<"-"<<tree[i].r<<endl;
//      }
      double ans = 0;
      for (int i=0;i<nums-1;i++)
      {
          int l = binary(ss[i].l,0,m-1);//二分找到s[i].l对应的离散化后的值
          int r = binary(ss[i].r,0,m-1)-1;//二分找到右端点但是由于需要把点转区间,因此减一
//          cout<<ss[i].l<<"->"<<l<<" ";
//          cout<<ss[i].r<<"->"<<r<<" ";
//          cout<<ss[i+1].h<<"-"<<ss[i].h<<endl;
          update(1,l,r,ss[i].f);//更新区间
          ans+=(ss[i+1].h-ss[i].h)*tree[1].len;
      }
        printf("Test case #%d\n", ++Case);
        printf("Total explored area: %.2f\n\n", ans);
  }
  return 0;
}

原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10357667.html

时间: 2024-08-08 11:04:30

HDU - 1542 扫描线入门+线段树离散化的相关文章

HDU 1542 Atlantis (线段树求矩阵覆盖面积)

题意:给你n个矩阵求覆盖面积. 思路:看了别人的结题报告 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1:另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1.根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序 #include <iostream> #include <stdio.h

hdu 5124 lines (线段树+离散化)

lines Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 620    Accepted Submission(s): 288 Problem Description John has several lines. The lines are covered on the X axis. Let A is a point which

HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11551    Accepted Submission(s): 4906 Problem Description There are several ancient Greek texts that contain descriptions of the fabled

【HDU】5249-KPI(线段树+离散化)

好久没写线段树都不知道怎么写了... 很easy的线段树二分问题 #include<cstdio> #include<set> #include<queue> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; #define lson (pos<<1) #define rson (pos<<1|1) const

HDU 1542 Atlantis(线段树扫描线&#183;面积并)

题意  给你一些矩形的左下和右上的坐标  求这些矩形的面积并 最基础的扫描线  理解了就是个水题了  先看一些图吧                                恩  看完了有什么感觉没有  那些红色的线就可以当作传说中的扫描线  就像从左到右扫描嘛  可以发现  矩形有竖直边的地方就有这些线  这些线把把拼在一起的矩形切成了一个个的小矩形  我们把这些小矩形的面积加起来不就是要求的面积吗 那么现在这些小矩形的面积怎么求呢  长乘宽嘛  长是什么  两条红线之间的距离  恩  我

HDU 1199 &amp;&amp; ZOJ 2301 线段树离散化

一段长度未知的线段,一种操作:a b c ,表示区间[a,b]涂为颜色C,w代表白色,b代表黑色,问最终的最长连续白色段,输出起始位置和终止位置 离散化处理,和平常的离散化不同,需要把点化成线段,左闭右开,即对于一段区间[a,b],转化成区间[a,b+1) #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct node { i

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #

HDU 1255 覆盖的面积 (扫描线 线段树 离散化)

题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了,因为虽然现在都不等于 2,但是之前的那个线段加上现在的已经覆盖2次了. 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include &