poj 1151 Atlantis “线段树维护关键值”+“离散化”+“扫描线法”
来源:互联网 发布:2017优化重组数学答案 编辑:程序博客网 时间:2024/06/12 00:25
Description
Input
The input file is terminated by a line containing a single 0. Don't process it.
Output
Output a blank line after each test case.
Sample Input
210 10 20 2015 15 25 25.50
Sample Output
Test case #1Total explored area: 180.00
Source
[Submit] [Go Back] [Status] [Discuss]
题目大意:
n个矩形,给出所有矩形的左上顶点坐标和右下顶点坐标,求解举行面积并。
解题思路:
第一次接触求解矩形面积并的题目,首先找了网上的代码和方法学习了一下。
这里使用的是用“线段树维护关键值”+“离散化”+“扫描线法”的方法。
(1)首先,因为横纵坐标的范围比较大,不能直接用横纵坐标来建立线段树。
所以可以用一个y数组来记录所有的纵坐标,然后排序,去除重复元素。再用这个数组的下标来建立线段树。
这样,在用到线段树求取矩形纵边长的时候就可以用线段树节点的左右端点作为索引求解实际的纵坐标了。
(2)接下来说一下线段树的作用,这里主要是维护一个len值。
线段树的节点有两个域:
一个是cover,用来表示之前是否有能够与当前边组成矩形的边。当遇到一条左边时,就cover++,遇到一条右边时就cover--。
这样每当扫描线经过一个完整的矩形后就相当于cover的值没有改变了。
另一个域是len,用来表示加入当前边之后可用来求解面积并的边长值。这么一来,扫描时,每加入一条边只需要ans加上len*(上一条边的x-当前边的x)即可。
而这个len值在每次加入边的时候都更新到根节点,tree[1]上,直接使用tree[1].len即可。
注意:
这里采用的是“与y轴平行的扫描线”,那么需要离散y坐标。如果采用的是“与x轴平行的扫描线”,则离散横坐标。
自己还是讲不很清楚,如果有疑惑可以再到这来看看,里面还有另外一种实现:
http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html
下面是我的ac代码:
#include <iostream>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#include <memory.h>#include <string>#include <vector>#include <list>#include <map>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <numeric>#include <functional>#define maxn 500using namespace std;int n,len;struct node{ int l; int r; int cover; double len;};node tree[5*maxn];struct LINE{ double x; double y_up,y_down; int l_or_r;};LINE line[maxn];double y[maxn];int findindex(double yy) //二分查找{ int l=0,r=len; while(l<=r){ int mid=(l+r)/2; if(yy==y[mid]){ return mid; } else if(yy>y[mid]){ l=mid+1; } else{ r=mid-1; } } return l;}int comp(const LINE &a,const LINE &b){ return a.x<b.x;}void build(int i,int l,int r){ tree[i].l=l; tree[i].r=r; tree[i].len=0; tree[i].cover=0; if(l+1==r){ return ; } int mid=(l+r)/2; build(2*i,l,mid); build(2*i+1,mid,r);}void update(int i,int l,int r,int cover){ if(tree[i].l>r || tree[i].r<l) return; if(tree[i].l>=l && tree[i].r<=r) { tree[i].cover+=cover; if(tree[i].cover) //如果cover大于1,那么整段都可用于与下一线段求并面积 tree[i].len=y[tree[i].r]-y[tree[i].l]; else if(tree[i].l+1==tree[i].r) //如果cover等于零,又到了叶子线段,那么可用线段长度就为零了 tree[i].len=0; else //如果cover等于零,那么以为着,之前没有可以和当前边组成矩形的边,且没到叶子节点,直接计算一下len tree[i].len=tree[2*i].len+tree[2*i+1].len; return; } update(2*i,l,r,cover); update(2*i+1,l,r,cover); //因为先处理完当前节点的子孙节点,才执行下面的判断更新语句,所以最后可以用于求面积并的len存储在了根节点 if(tree[i].cover) //如果cover大于1,那么整段都可用于求并面积 tree[i].len=y[tree[i].r]-y[tree[i].l]; else if(tree[i].l+1==tree[i].r) //如果cover等于零,又到了叶子线段,那么可用线段长度就为零了 tree[i].len=0; else //如果cover等于零,那么以为着,之前没有可以和当前边组成矩形的边,且没到叶子节点,直接计算一下len tree[i].len=tree[2*i].len+tree[2*i+1].len;}int main(){ int cas=1; while(1){ scanf("%d",&n); if(!n) break; int m=0; for(int i=0;i<n;i+=1){ double a1,b1,a2,b2; scanf("%lf %lf %lf %lf",&a1,&b1,&a2,&b2); y[m]=b1; //y存储所有的y坐标 line[m].x=a1; line[m].y_up=b1; line[m].y_down=b2; line[m++].l_or_r=1; y[m]=b2; //y存储所有的y坐标 line[m].x=a2; line[m].y_up=b1; line[m].y_down=b2; line[m++].l_or_r=-1; } sort(y,y+m); len=1; for(int i=1;i<m;i+=1){ //离散化,并且去除重复的纵坐标 if(y[i-1]!=y[i]){ y[len++]=y[i]; } } len--; build(1,0,len); sort(line,line+m,comp); double ans=0; printf("Test case #%d\n",cas++); for(int i=0;i<m-1;i+=1){ int a=findindex(line[i].y_down); //用line的y值二分出对应的y数组的下标 int b=findindex(line[i].y_up); update(1,b,a,line[i].l_or_r); ans+=tree[1].len*(line[i+1].x-line[i].x); //tree[1].len已经保留了整个树与line[i+1]所能求并面积的长度 } printf("Total explored area: %.2lf\n\n",ans); } return 0;}
- poj 1151 Atlantis “线段树维护关键值”+“离散化”+“扫描线法”
- POJ 1151 Atlantis 离散化 + 扫描线 + 线段树
- POJ 1151 Atlantis 扫描线+离散化+线段树
- POJ 1151 Atlantis(线段树+离散化+扫描线)
- poj-1151 Atlantis(线段树+离散化+扫描线)
- poj 1151 Atlantis (线段树+扫描线+离散化)
- 【POJ】1151 Atlantis(线段树+扫描线+离散化)
- poj 1151 Atlantis 线段树+离散化+扫描线
- poj 1151 Atlantis(线段树+离散化+扫描线)
- poj 1151 Atlantis(线段树+离散化+扫描线)
- POJ 1151 Atlantis 线段树+离散化+扫描线
- poj 1151 Atlantis 线段树扫描线+离散化
- POJ 1542 Atlantis (线段树+扫描线+离散化)
- Atlantis(扫描线+线段树+离散化)
- pku 1151 Atlantis(线段树+离散化+扫描线)
- 【线段树 + 离散化 + 扫描线】poj 1151 Atlantis 矩形面积并
- POJ题目 1151|| HDOJ 题目1542Atlantis(线段树+离散化+扫描线)
- POJ 1151 & HDU 1542 Atlantis(扫描线模板 线段树 离散化)
- 017
- Python String和PyQt QString的区别(转) http://blog.sina.com.cn/s/blog_4b5039210100h9kp.html
- WebView学习2
- 转载小满的
- Fragment嵌套Fragment的时候容易出现白屏的现象
- poj 1151 Atlantis “线段树维护关键值”+“离散化”+“扫描线法”
- C++获取系统时间
- 二维码,你真的了解吗?
- HOJ 12899 A+B Bucharest, Romania 2013
- Qt 的QString类的使用
- openCV 操作像素矩阵
- 傻傻的创业者(上)
- 大型网站架构演变和知识体系
- 大数