poj 1151 求矩形面积并 (线段树扫描线)

题意:

给出n个矩形的左下角和右上角坐标,求这n个矩形所构成的面积

思路:

线段树扫描线

这是第一次做到线段树扫描线,刚开始也不懂

如果不懂,可以看:

http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html

和 http://www.faceye.net/search/69289.html

我是看第一个链接弄懂的 然后学习了第二位的方法

代码上也有比较详细的注释,想可以帮到大家

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 205;

struct Line{
    double x;//存的是线段的x坐标
    double y1,y2;//存的是线段的下、上两个端点
    double f;//f是用来记录重叠情况的,可以根据这个来计算node中的c
}line[maxn*2];
//把一段段平行于y轴的线段表示成数组,
//x是线段的x坐标,y1 y2是线段对应的下端点和上端点
//一个矩形,左侧的边的f = 1,右侧的边  f= -1
//f是用来记录重叠情况的,可以根据这个来计算node中的c

double y[maxn*2];//用来记录y坐标,排序之后用来给线段树中的左右实际结点赋值,见代码build部分

//线段树的节点总数,大概要是线段个数的 4 倍(线段树和被操作的数据之间总是四倍关系)
const int maxnode = maxn << 2;
struct IntervalTree{
    double ll[maxnode],rr[maxnode],lf[maxnode],rf[maxnode],cnt[maxnode];
    //ll[]和rr[] 是用来标记线段树某一个区间的 经过离散化之后的 可以投影到实际坐标的 那个左右整点代号
    //lf rf 是用来记录真正的左右坐标的,用来计算该区间的长度
    int c[maxnode];//c是用来标记重叠情况的

    void build(int o, int l, int r){//递归建线段树
        ll[o] = l, rr[o] = r;
        cnt[o] = c[o] = 0;
        lf[o] = y[l], rf[o] = y[r];

        int mid = (l+r)>>1;
        int lc = o << 1, rc = o << 1 | 1;
        if(l + 1 == r) return;
        build(lc, l, mid);
        build(rc, mid, r);
    }
    void calen(int o){//用来计算区间o中的 线段被覆盖的长度
        if(c[o] > 0){
            cnt[o] = rf[o] - lf[o];
            return;
        }
        if(ll[o] + 1 == rr[o]) cnt[o] = 0;
        else{
            cnt[o] = cnt[o<<1] + cnt[o<<1|1];
        }
    }
    void update(int o, Line e){//新加入一条线段后 更新线段树
        double y1 = e.y1, y2 = e.y2;
        if(lf[o] == y1 && y2 == rf[o]){
            c[o] += e.f;
            calen(o);
            return;
        }
        int lc = o << 1, rc = o<<1|1;
        if(y2 <= rf[lc]) update(lc, e);
        else if(y1 >= lf[rc]) update(rc, e);
        else{
            Line tmp = e;
            tmp.y2 = rf[lc];
            update(lc, tmp);
            tmp = e;
            tmp.y1 = lf[rc];
            update(rc, tmp);
        }
        calen(o);
    }
}tree;

bool cmp(Line a, Line b){
    return a.x < b.x;
}
int main(){
    int n;
    int cas = 0;
    while(scanf("%d",&n) != EOF){
        if(n == 0) break;

        double y1,y2,x1,x2;
        int t = 1;
        for(int i = 1; i <= n; i++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);

            //这是一个处理和保存矩形左右两条边,并且对坐标进行离散化的过程
            //一个矩形 对应的是两条线段,左面一条(f = 1)右面一条(f = -1)
            line[t].x = x1;
            line[t].y1 = y1;
            line[t].y2 = y2;
            line[t].f = 1;
            y[t] = y1;
            t++;
            line[t].x = x2;
            line[t].y1 = y1;
            line[t].y2 = y2;
            line[t].f = -1;
            y[t] = y2;
            t++;
        }

        sort(y+1, y+t);//对y坐标按照从小到大的顺序排序,这是为了建立线段树,排完序才能离散地分成许多个区间
        sort(line+1, line+t, cmp);//从左到右扫描的话,应该保证在左边的线段先被扫到,
                                  //这里的排序就是让左边的线段在前面(按照x坐标从小到大排序)

        double res = 0;
        tree.build(1,1,t-1);
        //每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边
        //的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,
        //就能得到最后的面积。
        tree.update(1,line[1]);//先扫地一条边
        for(int i = 2; i < t; i++){
            res += tree.cnt[1] * (line[i].x - line[i-1].x);//用 高度*覆盖长度
            tree.update(1, line[i]);//扫描当前边
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n",++cas,res);
    }
    return 0;
}
时间: 2024-10-13 01:19:44

poj 1151 求矩形面积并 (线段树扫描线)的相关文章

poj-1151矩形面积并-线段树

title: poj-1151矩形面积并-线段树 date: 2018-10-30 22:35:11 tags: acm 刷题 categoties: ACM-线段树 概述 线段树问题里的另一个问题,,,矩形面积并,,,, 之前看lazy更新时看到下面这个的讲解,,,一大堆文字还有一大堆的图,,,,当时果断跳过,,, 今天花了一下午加一晚上的时间看了看这块知识,,,然后尝试自己写出代码,,,算是简单的了解一下这块,,, 题意 这道矩形面积并问题的大意是给很多个矩形,,矩形之间可能有交集,,,然后

HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21978    Accepted Submission(s): 8714 Problem Description There are several anc

poj 1151 Atlantis(矩形面积并)

题意:每组给出矩形左上角和右下角坐标,求矩形面积并: 思路:沿水平方向计算面积并:(切成水平条): #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int maxn=500; struct node{ double x; int l,r,t; //t为上下边标志

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

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

poj 1151(离散化+矩形面积并)

题目链接:http://poj.org/problem?id=1151 关于离散化,这篇博客讲的很好:http://www.cppblog.com/MiYu/archive/2010/10/15/129999.aspx 我线段树还是不会写这个.. 借个图: ///离散化 #include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <cm

POJ1151Atlantis 矩形面积并[线段树 离散化 扫描线]

Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 21734   Accepted: 8179 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of

POJ 2482 Stars in Your Window 线段树扫描线

Stars in Your Window Description Fleeting time does not blur my memory of you. Can it really be 4 years since I first saw you? I still remember, vividly, on the beautiful Zhuhai Campus, 4 years ago, from the moment I saw you smile, as you were walkin

HDU 1255 覆盖的面积 ——(线段树+扫描线)

又做了一题扫描线以后对节点的覆盖标记理解的更加深刻了. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #define t_mid (l+r>>1) 5 #define ls (o<<1) 6 #define rs (o<<1|1) 7 #define lson ls,l,t_mid 8 #define rson rs,t_mid+1,

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

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