HDU1542--Atlantis(扫描线)

给N个矩形的端点坐标,求矩形覆盖面积和。

原理很简单,从左到右扫描,线段树记录的是纵向覆盖的长度。区间更新。因为坐标是实数而且很大,所以需要离散化。

WA+RE+CE+MLE+。。。一共错了二十多次。用了最蠢的办法,最后发现错在初始化的时候,构造函数参数我写成了int。。蠢哭。。。

AC代码:

#include <bits/stdc++.h>
#define clr(x,c) memset(x,c,sizeof(x))

using namespace std;
const int N = 20005;

struct ScanLine {
    double x;
    double upY, downY;
    int flag;   // 入边1 出边-1
    bool operator<(const ScanLine a) const {
        return x < a.x;
    }
    ScanLine() {}
    ScanLine(double x, double y1, double y2, int f) : x(x), upY(y1), downY(y2), flag(f) {}
} line[N];

double tr[N];
int cover[N];
double yy[N];

#define lson (o<<1)
#define rson (o<<1|1)
#define mid (l+r>>1)
int yl, yr, v;
void pushup(int o, int l, int r)
{
    if (cover[o]) tr[o] = yy[r] - yy[l];
    else if (l + 1 == r) tr[o] = 0;         // 叶子
    else tr[o] = tr[lson] + tr[rson];
}

void update(int o, int l, int r)
{
    if (yl > r || yr < l) return ;
    if (yl <= l && yr >= r) {
        cover[o] += v;
        pushup(o, l, r);
        return ;
    }
    if (l + 1 == r) return ;                // 不包含的叶子节点要退出,否则死循环T^T
    if (yl <= mid) update(lson, l, mid);
    if (yr > mid) update(rson, mid, r);     // 注意这里不是mid+1 因为mid~mid+1一段的距离也要算
    pushup(o, l ,r);
}

int main()
{
    int n;
    int cas = 0;
    while (~scanf("%d", &n) && n) {
        int cnt = 0;
        double x1, y1, x2, y2;
        for (int i = 0; i < n; ++i) {
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            line[++cnt] = ScanLine(x1, y2, y1, 1);
            yy[cnt] = y1;
            line[++cnt] = ScanLine(x2, y2, y1, -1);
            yy[cnt] = y2;
        }
        sort(yy + 1, yy + cnt + 1);
        sort(line + 1, line + cnt + 1);
        int len = unique(yy + 1, yy + cnt + 1) - yy - 1;
        clr(cover, 0);
        clr(tr, 0);
        double ans = 0;
        for (int i = 1; i <= cnt; ++i) {
            ans += tr[1] * (line[i].x - line[i - 1].x);
            yl = lower_bound(yy+1, yy + len + 1, line[i].downY) - yy;
            yr = lower_bound(yy+1, yy + len + 1, line[i].upY) - yy;
            v = line[i].flag;
            update(1, 1, len);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", ++cas, ans);
    }
	return 0;
}

还有一种方法,比较好理解,和平时的线段树比较像,就是对于每个区间求[l, r-1],算的时候右边加一,这样递归的时候就不用考虑叶子节点了。

#include <bits/stdc++.h>
#define clr(x,c) memset(x,c,sizeof(x))
using namespace std;
const int N = 20005;

struct ScanLine {
    double x;
    double upY, downY;
    int flag;   // 入边1 出边-1
    bool operator<(const ScanLine a) const {
        return x < a.x;
    }
    ScanLine() {}
    ScanLine(double x, double y1, double y2, int f) : x(x), upY(y1), downY(y2), flag(f) {}
} line[N];

double tr[N];
int cover[N];
double yy[N];

#define lson (o<<1)
#define rson (o<<1|1)
#define mid ((l+r)>>1)
int yl, yr, v;

void pushup(int o, int l, int r)
{
    if (cover[o] > 0) tr[o] = yy[r+1] - yy[l];
    else if (l == r) tr[o] = 0;
    else tr[o] = tr[lson] + tr[rson];
}

void update(int o, int l, int r)
{
    if (yl > r || yr < l) return ;
    if (yl <= l && yr >= r) {
        cover[o] += v;
        pushup(o, l, r);
        return ;
    }
    if (yl <= mid) update(lson, l, mid);
    if (yr > mid) update(rson, mid + 1, r);
    pushup(o, l ,r);
}

int main()
{
    int n;
    int cas = 0;
    while (~scanf("%d", &n) && n) {
        int cnt = 0;
        double x1, y1, x2, y2;
        for (int i = 0; i < n; ++i) {
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            line[++cnt] = ScanLine(x1, y2, y1, 1);
            yy[cnt] = y1;
            line[++cnt] = ScanLine(x2, y2, y1, -1);
            yy[cnt] = y2;
        }
        sort(yy + 1, yy + cnt + 1);
        sort(line + 1, line + cnt + 1);
        int len = unique(yy + 1, yy + cnt + 1) - yy - 1;
        clr(cover, 0);
        clr(tr, 0);
        double ans = 0;
        for (int i = 1; i <= cnt; ++i) {
            ans += tr[1] * (line[i].x - line[i - 1].x);
            yl = lower_bound(yy+1, yy+len+1, line[i].downY) - yy;
            yr = lower_bound(yy+1, yy+len+1, line[i].upY) - yy - 1;
            v = line[i].flag;
            update(1, 1, len-1);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", ++cas, ans);
    }
	return 0;
}
时间: 2024-11-09 15:40:31

HDU1542--Atlantis(扫描线)的相关文章

POJ 1151 Atlantis 扫描线+线段树

点击打开链接 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17252   Accepted: 6567 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa

hdu1542 Atlantis (线段树+扫描线+离散化)

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

hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> #include <algorithm> #define MAXN 110 #define LL ((rt<<1)+1) #define RR ((rt<<1)+2) using namespace std; int n; struct segment{ double l

HDU-1542 Atlantis 【线段树+扫描线】

Problem 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 the island. But unfortunately, these maps describe different regions of Atlantis. You

POJ 1151 HDU 1542 Atlantis(扫描线)

题目大意就是:去一个地方探险,然后给你一些地图描写叙述这个地方,每一个描写叙述是一个矩形的右下角和左上角.地图有些地方是重叠的.所以让你求出被描写叙述的地方的总面积. 扫描线的第一道题,想了又想,啸爷还给我讲了讲,最终有点理解了啊. 先说扫描线:书上说扫描线不是一个物体.而是一个概念. 在计算几何中的作用类似于图论中的bfs与dfs.所以还是须要多做题目来体会一下啊. 这道题目的做法是:离散化x坐标.然后依照y坐标的大小进行排序,每一条保存它的左边界的位置与右边界的位置.以及自身的高度. 还有就

hdu-1542 Atlantis(离散化+线段树+扫描线算法)

题目链接: Atlantis Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/32768 K (Java/Others) Problem Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include ma

hdu1542 Atlantis

Problem 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 the island. But unfortunately, these maps describe different regions of Atlantis. You

poj1151 Atlantis——扫描线+线段树

题目:http://poj.org/problem?id=1151 经典的扫描线问题: 可以用线段树的每个点代表横向被矩形上下边分割开的每一格,这样将一个矩形的出现或消失化为线段树上的单点修改: 每个格子记录两个值:c(矩形存在情况),sum(对当前答案作出贡献的长度): 将y离散化作为建树的依据: 一开始没想到线段树上的点应该是横向的格子,写了个乱七八糟: #include<iostream> #include<cstdio> #include<cstring> #i

POJ 1151 Atlantis(扫描线)

题目原链接:http://poj.org/problem?id=1151 题目中文翻译: POJ 1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25769   Accepted: 9477 Description 有几个古希腊文本包含传说中的亚特兰蒂斯岛的描述. 其中一些文本甚至包括岛屿部分地图. 但不幸的是,这些地图描述了亚特兰蒂斯的不同区域. 您的朋友Bill必须知道地图的总面积. 你(不

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放