线段树+扫描线求矩形面积的并

POJ 1151 Atlantis(线段树+扫描线)

参考博客https://blog.csdn.net/lwt36/article/details/48908031

上面博客的原理讲解非常清楚

在这我只对代码的模板分层讲解

一些基础的

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#define lson rt<<1,left,mid
#define rson rt<<1|1,mid,right
#define eps 1e-8
using namespace std;
const int maxn = 222;
//线段树
struct node{
    double len;
    int cover;
}tree[maxn << 2];

线段树中len 是覆盖标记的长度,也就是扫描线扫过后的所有覆盖的长度

//离散化
double X[maxn];
int N;

以上是离散化的数组,因为x是浮点值,所以先映射到一个数组里,然后排序————从小到大

再利用一下代码

sort(X,X+N);

int tn = unique(X,X+N) - X; build(1,0,tn-1);

得到不同x的离散范围

这样就可以建树了

struct edge{
    double x1,x2,y;
    int flag;
}e[maxn<<2];
bool cmp(edge a,edge b)
{
    if(a.y != b.y)return a.y < b.y;
    else return a.flag > b.flag;
}
int cnt;
void add(double x1,double x2,double y,double xx,int flag)
{
    e[cnt].x1 = x1;
    e[cnt].x2 = x2;
    e[cnt].y = y;
    e[cnt].flag = flag;
    X[N++] = xx;
    cnt++;
}
void init()
{
    cnt = 0;
    N = 0;
}

以上是对边的存储,排序,加边,和整体的初始化操作

接下来我们建树:主要是初始化len和cover的值  

void build(int rt,int left,int right)
{
    tree[rt].len = 0.0;
    tree[rt].cover = 0;
    if(left + 1 == right)return;
    int mid = (left + right) >> 1;
    build(lson);
    build(rson);
}

然后是扫描线更新,进本的更新,比较时利用离散化时的映射进行比较更新,找到区间更新cover,没有找到继续向下,知道叶子节点

中间顺便进行pushup向上维护

void updata(int rt,int left,int right,double x1,double x2,int v)
{
    if(Equal(X[left],x1)&&Equal(X[right],x2))
    {
        tree[rt].cover += v;
    }
    if(left + 1 < right)
    {
        int mid = (left + right) >> 1;
        if(x2 <= X[mid]+eps)
            updata(lson,x1,x2,v);
        else if(x1 >= X[mid] - eps)
            updata(rson,x1,x2,v);
        else
        {
            updata(lson,x1,X[mid],v);
            updata(rson,X[mid],x2,v);
        }
    }
    pup(rt,left,right);
}

维护应该比较好懂

bool Equal(double x,double y)
{
    return abs(x-y) <= eps;
}
void pup(int rt,int left,int right)
{
    if(tree[rt].cover)
        tree[rt].len = X[right] - X[left];
    else if(left + 1 == right)
        tree[rt].len = 0.0;
    else
        tree[rt].len = tree[rt<<1].len + tree[rt<<1|1].len;
}

到此就差不多了

int main()
{
    int cas = 1;
    int n;
    double x1,y1,x2,y2;
    while(~scanf("%d",&n),n)
    {
        init();
        for(int i = 1;i <= n;++i)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            add(x1,x2,y1,x1,1);
            add(x1,x2,y2,x2,0);
        }
        sort(e,e+cnt,cmp);
        //从小到大的离散化,把值都映射到了1 - N
        sort(X,X+N);

        int tn = unique(X,X+N) - X;
        build(1,0,tn-1);
        double ans = 0.0;
        double length = 0.0;
        for(int i = 0;i < cnt;i++)
        {
            if(e[i].flag == 1)
                updata(1,0,tn-1,e[i].x1,e[i].x2,1);
            else
                updata(1,0,tn-1,e[i].x1,e[i].x2,-1);

            if(i != 0)
                ans += length * (e[i].y - e[i-1].y);
            length = tree[1].len;
        }
        printf("Test case #%d\n",cas++);
        printf("Total explored area: %.2f\n\n",ans);

    }
    return 0;
}

原文地址:https://www.cnblogs.com/DF-yimeng/p/9468813.html

时间: 2024-11-10 07:09:12

线段树+扫描线求矩形面积的并的相关文章

线段树 : 求矩形面积的并 ---- hnu : 12884 Area Coverage

Area Coverage Time Limit: 10000ms, Special Time Limit:2500ms, Memory Limit:65536KB Total submit users: 16, Accepted users: 12 Problem 12884 : No special judgement Problem description In this day and age, a lot of the spying on other countries is done

hdu 1255 覆盖的面积 线段树扫描线求重叠面积

稀里糊涂打完了没想到1A了,心情还是很舒畅的,c和c++的四舍五入还是四舍六入遇积进位遇偶舍,我感觉很混乱啊,这道题我输出的答案是7.62,也就是遇偶舍了,可是我就手动处理一下进位问题,发现0.005 系统自动进位0.01了,尼玛啊,我一下子就混乱了,不是遇偶舍么,0也是偶数啊,怎么就进位了呢.最后我就不手动处理进位问题了,直接0.2lf%,虽然我输出的结果是7.62,但是提交也过了 这道题和poj1151,hdu1542差不多,扫描线详细讲解http://blog.csdn.net/young

hdu 1542(线段树+扫描线 求矩形相交面积)

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

【HDU 1542】Atlantis(线段树+离散化,矩形面积并)

求矩形面积并,离散化加线段树. 扫描线法: 用平行x轴的直线扫,每次ans+=(下一个高度-当前高度)*当前覆盖的宽度. #include<algorithm> #include<cstdio> #include<cstring> #define dd double #define ll long long #define N 201 using namespace std; struct P{dd s,e,h;int f;}p[N]; struct Tree{dd s

线段树扫描线 求矩阵的覆盖面积

题意:给出几个矩阵求这些矩阵覆盖的面积: 给出左上角与右下角 Sample Input 20 5 4 12 4 6 2 Sample Output 20 #include<bits/stdc++.h> #define LL long long #define lson l, m, rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int maxn = 5e3 + 10; const int Base

【POJ 1389】Area of Simple Polygons(线段树+扫描线,矩形并面积)

离散化后,[1,10]=[1,3]+[6,10]就丢了[4,5]这一段了. 因为更新[3,6]时,它只更新到[3,3],[6,6]. 要么在相差大于1的两点间加入一个值,要么就让左右端点为l,r的线段树节点表示到x[l]到x[r+1]的区间. 这样tree[l,r]=tree[l,m]+tree[m+1,r]=[x[l],x[m+1]]+[x[m+1],x[r+1]] #include<iostream> #include<algorithm> #include<cstdio

hdu 1255(线段树 扫描线) 覆盖的面积

http://acm.hdu.edu.cn/showproblem.php?pid=1255 典型线段树辅助扫描线,顾名思义扫描线就是相当于yy出一条直线从左到右(也可以从上到下)扫描过去,此时先将所有的横坐标和纵坐标排序 因为是从左到右扫描,那么横坐标应该离散化一下 当扫描线依次扫描的时候,依次扫描到的纵区间在线段树中查找,依据是上边还是下边记录,上边就是-1,下边就是+1, 如果某区间记录值为0的时候,代表没有被覆盖,为1的时候代表覆盖一次,为2代表覆盖两次(不会出现为负数的情况) 最后将依

HDU 1255 覆盖的面积(线段树扫描线求面积的交)

Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 注意:本题的输入数据较多,推荐使用scanf读入数据. Out

HDU 1828 Picture(线段树扫描线求周长)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4475    Accepted Submission(s): 2207 Problem Description A number of rectangular posters, photographs and other pictures of the same shap