POJ 1542 Atlantis(线段树 面积并+离散化)
来源:互联网 发布:ps淘宝详情页的计算法 编辑:程序博客网 时间:2024/06/05 18:24
参考网址:http://blog.csdn.net/sunmenggmail/article/details/7984589
Problem Description
The input file is terminated by a line containing a single 0. Don’t process it.
Output a blank line after each test case.
210 10 20 2015 15 25 25.50
Test case #1Total explored area: 180.00
题意:题意很简单,就是求矩形面积的并
给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1)、(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序。
上图中,红色的字体表示的是该线段的左右标志,绿色字体为当前更新到当前线段的cover值。刚刚开始的时候,线段树上的cover值都为0,但第一根线段(x==0)插入线段树的之后,我们将线段树上的cover加上该线段的cover,那么,此时线段树上被该线段覆盖的位置上的cover的值就为1,下次再插入第二根线段(x==1)此时发现该线段所覆盖的区间内,有一部分线段树的cover为0,另有一部分为1,仔细观察,但插入第二个线段的时候,如果线段树上cover已经为1的那些区间,和现在要插入的第二根线段之间,是不是构成了并面积?还不明白?看下图,绿色部分即为插入第二根线段后得到的并面积
#include <iostream>#include <algorithm>#include <stdio.h>using namespace std;const int maxn=110;struct LINE{ double x, y_down, y_up; int flag; bool operator<(const LINE &a)const ///按照x从小到大的顺序排序 { return x<a.x; }}line[2*maxn];struct TREE{ double x,y_down, y_up; int cover; ///用以表示加进线段树中的线段次数 bool flag; ///标记叶子节点}tree[1000*maxn];double y[2*maxn];void build(int i, int l, int r) ///当前节点下标,l , r 线段树建立左右线数组下标{ tree[i].x = -1; //-1表示该区间已经没有线段 tree[i].cover = 0; //表示该区间上有多少条线段;左边线段加进去则++,右边线段加进去则-- tree[i].y_down = y[l]; tree[i].y_up = y[r]; tree[i].flag = false; if(l+1==r) { tree[i].flag = true; //flag==true表示达到了叶子节点 return; } int mid=(l+r)>>1; build(2*i, l, mid); build(2*i+1, mid, r);}double insert(int i, double x, double l, double r, int flag) //flag表示为左边还是右边{ if ( r<=tree[i].y_down || l>=tree[i].y_up ) return 0; if (tree[i].flag) /// 叶子节点 { if (tree[i].cover > 0) /// 该区域的面积存在,且未经计算 { double temp_x = tree[i].x; double ans=( x-temp_x )*(tree[i].y_up - tree[i].y_down); tree[i].cover += flag; tree[i].x = x; //定位上一次的x return ans; } else ///虽然是叶子节点,但是需要更新当前的线段覆盖标记 { tree[i].cover += flag; tree[i].x = x; ///更新最新x return 0; } } return insert(2*i, x, l, r, flag)+insert(2*i+1, x, l, r, flag); ///不是叶子节点就往下递归}int main( ){ // freopen("d:\\in.txt","r",stdin); int Case=0,n,index; double x1, y1, x2, y2; while(~scanf("%d",&n) && n) { index = 1; for (int i=1; i<=n; i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); y[index] = y1; line[index].x = x1; line[index].y_down = y1; line[index].y_up = y2; line[index++].flag = 1; //1表示左边 y[index] = y2; line[index].x = x2; line[index].y_down = y1; line[index].y_up = y2; line[index++].flag = -1; //-1表示右边 } sort(&y[1], &y[index]); //把所有的纵坐标按从小到大排序,把1写成了0,WA一次 sort(&line[1], &line[index]); build(1, 1, index-1); double ans=0; for (int i=1;i<index; i++) ///将线line从左向右遍历 ans+=insert(1, line[i].x, line[i].y_down, line[i].y_up, line[i].flag); printf("Test case #%d\nTotal explored area: %.2f\n\n", ++Case, ans); } return 0;}
开始感觉和POJ 2528应该是一样的啊,为什么没有去重啊,于是写一个去重的,果断AC,之后想为什么?其实也很简单,因为在这里的是通过ans=( x-temp_x )*(tree[i].y_up - tree[i].y_down)这个公式求面积的,并且在Build的时候是排过序的,所以两个相邻的也就是叶子节点的(tree[i].y_up - tree[i].y_down)如果有重点就为0了,这样该段算出来的面积也就是0了,没有影响,但是感觉还是先去重之后比较清晰。
#include <iostream>#include <algorithm>#include <stdio.h>using namespace std;const int maxn=110;struct LINE{ double x, y_down, y_up; int flag; ///表示一个矩形的左边还是右边 bool operator<(const LINE &a)const ///按照x从小到大的顺序排序 { return x<a.x; }}line[2*maxn];struct TREE{ double x,y_down, y_up; int cover; ///用以表示加进线段树中的线段次数 bool flag; ///标记叶子节点}tree[1000*maxn];double y[2*maxn];void build(int i, int l, int r) ///当前节点下标,l , r 线段树建立左右线数组下标{ tree[i].x = -1; //-1表示该区间已经没有线段 tree[i].cover = 0; //表示该区间上有多少条线段;左边线段加进去则++,右边线段加进去则-- tree[i].y_down = y[l]; ///离散化 tree[i].y_up = y[r]; ///离散化 tree[i].flag = false; if(l+1==r) ///叶子节点是用来对每个y段进行遍历用的 { tree[i].flag = true; //flag==true表示达到了叶子节点 return; } int mid=(l+r)>>1; build(2*i, l, mid); build(2*i+1, mid, r);}double insert(int i, double x, double l, double r, int flag) //flag表示为左边还是右边{ ///父节点 当前线段的x值 y_Down y_Up if ( r<=tree[i].y_down || l>=tree[i].y_up ) return 0; if (tree[i].flag) /// 叶子节点 { double ans = 0; if (tree[i].cover > 0) /// 该区域的面积存在,且未经计算 { double temp_x = tree[i].x; ans=( x-temp_x )*(tree[i].y_up - tree[i].y_down); } ///更新该线段最新的x坐标和被覆盖情况 tree[i].cover += flag; tree[i].x = x; //定位上一次的x return ans; } return insert(i<<1, x, l, r, flag)+insert(i<<1|1, x, l, r, flag); ///不是叶子节点就往下递归}int main( ){ // freopen("d:\\in.txt","r",stdin); int Case=0,n,index; double x1, y1, x2, y2; while(~scanf("%d",&n) && n) { index = 1; for (int i=1; i<=n; i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); y[index] = y1; line[index].x = x1; line[index].y_down = y1; line[index].y_up = y2; line[index].flag = 1; //1表示左边 index++; y[index] = y2; line[index].x = x2; line[index].y_down = y1; line[index].y_up = y2; line[index].flag = -1; //-1表示右边 index++; } sort(&y[1], &y[index]); //把所有的纵坐标按从小到大排序,把1写成了0,WA一次 sort(&line[1], &line[index]); int nCount=unique(&y[1],&y[index])-(&y[1]); build(1, 1, nCount); double ans=0; for (int i=1;i<index; i++) ///将线line从左向右遍历 ans+=insert(1, line[i].x, line[i].y_down, line[i].y_up, line[i].flag); printf("Test case #%d\nTotal explored area: %.2f\n\n", ++Case, ans); } return 0;}
- POJ 1542 Atlantis(线段树 面积并+离散化)
- HDOJ 1542 (POJ 1151) Atlantis 【线段树 离散化 扫描线 面积并】
- hdu 1542 Atlantis 线段树矩形面积并+离散化
- HDU-1542/POJ-1151 Atlantis(矩形并面积--线段树+离散化)
- poj 1151 Atlantis(矩形面积并,线段树+离散化)
- POJ 1151 Atlantis(线段树离散化求面积并)(C++)
- HDU 1542 Atlantis(离散化+扫描线(求并面积)+线段树)
- HDU 1542——Atlantis(线段树+面积并+离散化+扫描线)
- 【线段树 + 离散化 + 扫描线】poj 1151 Atlantis 矩形面积并
- hdu 1542 Atlantis 线段树+矩形面积并+离散化点
- POJ1151 (HDU 1542) Atlantis【矩形面积并,线段树+离散化+扫描线模板】
- HDU 1542 Atlantis(矩形面积并,线段树+离散化+线扫描)
- Atlantis(hdu1151,求面积并,线段树+离散化+扫描)
- HDU1542——Atlantis(扫描线,线段树,矩形面积并,离散化)
- POJ1151 Atlantis(线段树,扫描线,离散化,矩形面积并)
- POJ 1151 Atlantis 线段树面积并
- POJ 1542 Atlantis (线段树+扫描线+离散化)
- Hdu 1542/ POj 1151 Atlantis 线段树+矩形面积并
- 二叉搜索树的C++实现
- Android学习路线指南
- ArcGIS教程:了解路径距离分析(二)
- sql中创建主键非聚集索引和聚集索引
- payload data
- POJ 1542 Atlantis(线段树 面积并+离散化)
- asp.net验证码及怎么获取里面的数值(整合)
- jenkins邮件插件中的内容参数设置
- 详解apache log的%D到底包含什么时间
- 云客网SEO优化师分享近几年接私单的经历
- 计算机网络之面试常考题
- 【Codeforces Round 323 (Div 2)B】【贪心】Robot's Task 最少转弯次数拿走所有物品
- 【iOS】网络操作与AFNetworking
- 临时表、表变量、CTE的比较