HDU 1542 Atlantis (线段树 +离散化+ 扫描线)
2015-09-07 20:51
543 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542
题意 :给出几个矩形坐标的对角线,求矩形其覆盖面积。
对这样的一个矩形,我们构造两条线段,左条设为x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段设为x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段x从左到右进行排序。
样例矩形如图所示:
![](https://img-blog.csdn.net/20150907193810360)
开始时扫描线的位置:
我们设矩形左端的flag值为1,右端为-1;
将x坐标离散化,按顺序将x标号作为线段树区间;
![](https://img-blog.csdn.net/20150907201322151)
现在开始扫描,设每一个线段树区间有一个cover值来记录该区间有多少线段,刚开始cover值都为0;当x = 10插入线段树之后,我们将线段树上的cover加上该线段的flag,那么,此时线段树上被该线段覆盖的位置上的cover的值就为1;x = 20同理
![](https://img-blog.csdn.net/20150907201801505)
当插入x = 15时区间cover已经为1,计算并面积,并更改cover值,cover+=flag;
![](https://img-blog.csdn.net/20150907203710020)
当x = 20时区间cover为1,计算并面积,并更改cover值;
![](https://img-blog.csdn.net/20150907204413150)
最后,也就是说,我们插入某跟线段的时候,只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的位置 - 上一线段的位置)*(该区间的大小)
![](https://img-blog.csdn.net/20150907204856663)
题意 :给出几个矩形坐标的对角线,求矩形其覆盖面积。
对这样的一个矩形,我们构造两条线段,左条设为x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段设为x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段x从左到右进行排序。
样例矩形如图所示:
开始时扫描线的位置:
我们设矩形左端的flag值为1,右端为-1;
将x坐标离散化,按顺序将x标号作为线段树区间;
现在开始扫描,设每一个线段树区间有一个cover值来记录该区间有多少线段,刚开始cover值都为0;当x = 10插入线段树之后,我们将线段树上的cover加上该线段的flag,那么,此时线段树上被该线段覆盖的位置上的cover的值就为1;x = 20同理
当插入x = 15时区间cover已经为1,计算并面积,并更改cover值,cover+=flag;
当x = 20时区间cover为1,计算并面积,并更改cover值;
最后,也就是说,我们插入某跟线段的时候,只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的位置 - 上一线段的位置)*(该区间的大小)
#include<iostream> #include<algorithm> #include<cstdio> #include<string> #include<cstring> #include<cmath> #include<map> #include<iomanip> #include<set> #define inf 0x3f3f3f3f using namespace std; double y[222]; //保存纵坐标 struct line { double x; //线段的横坐标 double y_up,y_down;//线段的上端点和下端点 int flag ;//记录该线段是左线段还是右线段 bool operator < (const line &b)const{ //将x升序排序 return x < b.x; } }Line[222];//线数组 struct tree { double x; //该区间线段的横坐标 double y_up,y_down;//该区间线段的上下端点 int cover; //该区间有多少线段 bool isLeaf; //是否为叶子节点 }Tree[111111]; // 线段树数组 void build(int i , int l , int r)//i:数组下标;l:区间左值下标;r:区间右值下标. { Tree[i].x = -1; //-1表示该区间没有线段。 Tree[i].cover = 0;//表示该区间有多少线段。左线段加进去++1,右线段加进去--1。 Tree[i].y_up = y[r]; //该区间的上端点 Tree[i].y_down = y[l];//该区间的下端点 Tree[i].isLeaf = false; //不是叶子节点 if(l + 1 == r) { //是叶子结点则标记后终止。 Tree[i].isLeaf = true; return; } int mid = (l + r) / 2; build(i * 2 , l , mid); build(i * 2 +1 , mid , r);//注意:mid而不是mid+1. } double Insert(int i , double x , double y_up , double y_down , int flag ) { /*i:数组下标;x,y_down,y_up:线段各值;flag:标记左线段还是右线段。*/ if(y_up <= Tree[i].y_down || y_down >= Tree[i].y_up)return 0; //要插入的线段完全与该段线不搭嘎。 if(Tree[i].isLeaf) //若是叶子结点。 { if(Tree[i].cover > 0) //且cover大于0,即cover不等于0,表示该区间已有左线段。 { double s = (x - Tree[i].x)*(Tree[i].y_up - Tree[i].y_down); //计算面积 Tree[i].x = x; //更新横坐标。 Tree[i].cover += flag; //计数 return s; } else //cover==0,表示该区间还没有左线段,不能求面积 { Tree[i].x = x; Tree[i].cover += flag; return 0; } } //对叶子结点操作。 double s1 = Insert(i * 2 , x , y_up , y_down , flag); double s2 = Insert(i *2 + 1 , x , y_up , y_down , flag); return s1+s2; } int main() { int n,Case = 1; double x1,x2,y1,y2; while(~scanf("%d",&n)&&n) //输入n { int k = 0; for(int i = 1 ; i <= n ; i ++ ) //输入数据。 { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); Line[++k].x = x1; Line[k].y_up = y2; //把矩形的竖边化成线存入Line数组。 Line[k].y_down = y1; y[k] = y1; Line[k].flag = 1; Line[++k].x = x2; Line[k].y_up = y2; Line[k].y_down = y1; y[k] = y2; Line[k].flag = -1; } sort(Line + 1, Line + k + 1); //将线按x升序排列 ,注意sort函数的起始终止位置。 sort(y + 1 , y + k + 1); a04e //将所有纵坐标升序排列。 build (1 , 1 , 2 * n); //建树。 double S = 0; //存面积 for(int i = 1 ; i <= 2*n ; i ++ ) { S += Insert(1 ,Line[i].x , Line[i].y_up , Line[i].y_down,Line[i].flag); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",Case++ , S); } return 0; }
相关文章推荐
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- 探讨C语言的那些小秘密之断言
- C语言实现BMP转换JPG的方法
- 深入探讨C语言中局部变量与全局变量在内存中的存放位置
- C语言查找数组里数字重复次数的方法
- C语言泛型编程实例教程
- C语言中使用lex统计文本文件字符数
- 在C语言中转换时间的基本方法介绍
- C语言进制转换代码分享