`
Simone_chou
  • 浏览: 192652 次
  • 性别: Icon_minigender_2
  • 来自: 广州
社区版块
存档分类
最新评论

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

    博客分类:
  • HDOJ
 
阅读更多

覆盖的面积

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3534    Accepted Submission(s): 1731


Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.

 

 

Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

注意:本题的输入数据较多,推荐使用scanf读入数据.
 

 

Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
 

 

Sample Input
2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1
 

 

Sample Output

 

7.63
0.00

       思路:

       线段树 + 扫描线 + 离散化。len 维护该区间内已被覆盖的长度,one 维护这个区间内覆盖一次的长度,two 维护这个区间内被覆盖两次或者两次以上的长度。每个区间覆盖的长度 len 要始终等于 one + two。主要是 push_up 的不同:

void push_up (int node, int l, int r) {
        if (cover[node] >= 2) {
                len[node] = two[node] = yy[r] - yy[l];
                one[node] = 0;
        //当覆盖两次,则 one 应该为0
        } else if (cover[node] == 1) {
                len[node] = yy[r] - yy[l];
                two[node] = two[node << 1] + two[node << 1 | 1];
                two[node] += (one[node << 1] + one[node << 1 | 1]);
                one[node] = len[node] - two[node];
        //当覆盖一次,two 应该为左右儿子 two 之和,加上它这层在原来左右儿子 one 上的和
        //总长减去 two 的长度就是 one 的长度,
        } else if (r - l == 1) {
                len[node] = two[node] = one[node] = 0;
        //未被覆盖且是叶子节点则为 0
        } else {
                len[node] = len[node << 1] + len[node << 1 | 1];
                two[node] = two[node << 1] + two[node << 1 | 1];
                one[node] = one[node << 1] + one[node << 1 | 1];
        //未被覆盖且不是叶子节点则全为左右儿子各部分之和
        }
}

 

       AC:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAX = 2050 * 2 * 3;

typedef struct {
        double x, y1, y2;
        int temp;
}node;

node line[2050];
double yy[2050 * 2];
double one[MAX], two[MAX], len[MAX];
int cover[MAX];

bool cmp (node a, node b) {
        if (a.x != b.x) return a.x < b.x;
        return a.temp > b.temp;
}

void push_up (int node, int l, int r) {
        if (cover[node] >= 2) {
                len[node] = two[node] = yy[r] - yy[l];
                one[node] = 0;
        } else if (cover[node] == 1) {
                len[node] = yy[r] - yy[l];
                two[node] = two[node << 1] + two[node << 1 | 1];
                two[node] += (one[node << 1] + one[node << 1 | 1]);
                one[node] = len[node] - two[node];
        } else if (r - l == 1) {
                len[node] = two[node] = one[node] = 0;
        } else {
                len[node] = len[node << 1] + len[node << 1 | 1];
                two[node] = two[node << 1] + two[node << 1 | 1];
                one[node] = one[node << 1] + one[node << 1 | 1];
        }
}

void build (int node, int l, int r) {
        if (r - l == 1) {
                cover[node] = len[node] = 0;
                two[node] = one[node] = 0;
        } else {
                int mid = (r + l) >> 1;
                build(node << 1, l, mid);
                build(node << 1 | 1, mid, r);
                push_up(node, l, r);
        }
}

void updata (int node, int l, int r, int cl, int cr, int c) {
        if (cl > r || cr < l) return;
        if (cl <= l && cr >= r) {
                cover[node] += c;
                push_up(node, l, r);
                return;
        }
        if(r - l == 1) return;

        int mid = (r + l) >> 1;
        if (l <= mid) updata(node << 1, l, mid, cl, cr, c);
        if (r >= mid) updata(node << 1 | 1, mid, r, cl, cr, c);
        push_up(node, l, r);
}

int main() {
        int t;
        scanf("%d", &t);

        while (t--) {
                int n;
                scanf("%d", &n);

                int ans = 0, m = 0;
                while (n--) {
                        double x1, y1, x2, y2;
                        scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);

                        line[ans].x = x1;
                        line[ans].y1 = y1;
                        line[ans].y2 = y2;
                        line[ans++].temp = 1;

                        line[ans].x = x2;
                        line[ans].y1 = y1;
                        line[ans].y2 = y2;
                        line[ans++].temp = -1;

                        yy[m++] = y1;
                        yy[m++] = y2;
                }

                sort(yy, yy + m);
                m = unique(yy, yy + m) - yy;

                sort(line, line + ans, cmp);
                build(1, 0, m - 1);

                double res = 0;
                for (int i = 0; i < ans; ++i) {
                        int ll = lower_bound(yy, yy + m, line[i].y1) - yy;
                        int rr = lower_bound(yy, yy + m, line[i].y2) - yy;

                        if(i) res += two[1] * (line[i].x - line[i - 1].x);
                        
                        updata(1, 0, m - 1, ll, rr, line[i].temp);
                }

                printf("%.2lf\n", res);

        }

        return 0;
}

 

 

分享到:
评论

相关推荐

    线段树矩形面积并讲解

    ACM中对于矩形面积并用线段树+离散化+ 扫描线一类问题求解

    线段树.pdf

    离散化是处理大规模数据时的一个技巧,它可以将数据映射到一个较小的范围内,从而减少线段树的空间需求,并可能加快查询和更新的效率。 扫描线技术是处理与线段树相关的一些问题时使用的,它用于动态处理线段树中的...

    线段树汇总

    - Atlantis(1151):经典的扫描线求矩形面积交,通过离散化和线段树实现。 - Picture(1177):要求求解矩形周长的并,需要维护线段树中的多个信息。 - K-th Number(2155):使用线段树维护归并排序树,并采用...

    线段树题目

    - **POJ 1151**:结合了线段树和离散化的技巧来求解矩形面积的并集。这需要对输入的坐标进行离散化处理,以减少空间复杂度,并使用线段树维护区间信息。 - **POJ 1177**:求解矩形周长的并集。此题与POJ 1151类似,...

    ACM算法模板和pku代码

    离散化+线段树 灯光投影 网络赛取连续子序列问题 线段树+树状数组+并查集,转化为排队问题 离散化 离散化矩形切割,矩形覆盖面积统计 覆盖矩形周长统计 离散化矩形切割 灯光投影 搜索 导弹 Bfs+hash状态的抽象...

    思路列表1

    总结起来,这两个问题都需要高效的算法和数据结构来处理大规模数据,如扫描线、线段树和单调队列,以及离散化技术来优化处理时间。这些问题不仅出现在NOIP这样的编程竞赛中,也在实际的软件开发和数据分析中有着广泛...

    DK模板1

    离散化线段树扫描线 离散化线段树结合扫描线算法,能够有效地处理动态区间问题,例如区间加减、查询等,特别适合于处理连续区间上的操作。 ### 7. 数论 在编程竞赛中,数论技巧广泛应用于素数判断、模逆运算、中国...

    1151.zip_数据库编程_Visual_C++_

    在Visual C++环境中,开发者可以利用STL(Standard Template Library)中的容器和算法来实现线段树和离散化,同时还可以利用MFC(Microsoft Foundation Classes)或者ATL(Active Template Library)等库来方便地与...

    ACM巨全模板 .pdf

    4.扫描线 (矩形覆盖求面积) (矩形覆盖求周长) 5.凸包 (平面上最远点对) 6.求凸多边形的直径 7.求凸多边形的宽度 8.求凸多边形的最小面积外接矩形 9.半平面交 图论: 基础:前向星 1.最短路(优先队列dijkstra) 2.判断...

    参加ACM大赛应该准备哪些课程?.docx

    8. 线段树:基本操作和应用 9. 并查集:应用和高级用法 10. 判断点在多边形内、差分约束系统 数据结构部分 1. 树状数组:基本概念和应用 2. 并查集:基本概念和应用 3. 堆排序:基本概念和应用 4. 字符串匹配:KMP...

    算法知识LC模板.pdf

    21. 算法优化:包括快速幂优化、矩阵快速幂、树状数组的常用操作、扫描线技术等。 22. 算法模板和编程技巧:例如快速幂的模实现、n的阶乘的斯特林公式和欧拉公式、素数筛法的实现、线性同余方程组的中国剩余定理通...

    地理信息系统算法基础.rar

    2.19计算两条共线的线段的交点 2.20计算线段或直线与线段的交点 2.21求线段或直线与圆的交点 2.22中心点的计算 2.23过点作垂线 2.24作平行线 2.25过点作平行线 2.26线段延长 2.27三点画圆 2.28线段打断 ...

    常用算法.docx

    4. **计算几何中的算法**:如坐标离散化、扫描线算法和半平面交等,用于处理几何对象的计算问题。 **C++标准模板库的应用**: C++的STL(Standard Template Library)包含容器、迭代器、算法和函数对象,为编程...

    计算机图形学画圆程序

    对于填充操作,可能涉及到扫描线算法或者八叉树填充等技术。 图形用户界面(GUI)也是这个程序的一部分,可能使用了事件驱动编程模型,监听用户的点击和拖动操作,以动态改变圆心位置或半径。这涉及到了图形库的...

    Graphics Gems (Vol.1)

    - **Z 缓存三角形的扫描线深度梯度**: 介绍了一种计算Z缓存中三角形扫描线深度变化的方法。 - **模拟雾和霾**: 描述了如何在计算机图形学中模拟雾和霾的效果。 - **纹理贴图索引的解释**: 讨论了如何正确理解和使用...

    常用算法 (2).docx

    - **计算几何学**:包括**坐标离散化**、**扫描线算法**、**多边形的内核**和**几何工具的综合应用**。 最后,对于更高级的算法挑战,你可以学习: - **度限制最小生成树**和**第K最短路**。 - **最小树形图**和**...

    ACM所需小知识

    - **离散化与扫描**:通过离散化技术简化问题,并使用扫描线算法求解。 #### 数据结构 - **广度优先搜索**:一种图遍历算法,按层次顺序访问每个顶点。 - **验证括号匹配**:检查括号序列是否正确配对。 - **表达式...

    计算机图形学基础试题.pdf

    11. **多边形填充**:扫描线算法避免重复访问像素,但维护和排序代价高;边填充算法适合帧缓冲系统,但可能导致重复访问;边标志算法不能彻底解决重复访问问题。 12. **插值与逼近**:插值是确保函数经过所有给定点...

    计算机图形学试题a(软件学院2002级)答案.doc

    5. **裁剪**:是图形处理中的一个步骤,目的是去除不在视窗内的部分,保留可视部分,例如窗口裁剪、扫描线裁剪等。 6. **扫描转换算法**:用于将多边形转换成像素的算法,如六边形的填充,这里提到了使用活跃边表的...

    ACM算法合集

    首先对顶点按极角顺序排序,然后通过扫描线方法剔除内点,最终得到凸包上的顶点序列。 5. **最长递增子序列(LIS)**:在给定序列中寻找最长的严格递增子序列。可以采用动态规划或二分查找优化的贪心策略来求解。 ...

Global site tag (gtag.js) - Google Analytics