hdu 线段树 (矩形面积并+离散化+二分查找)
来源:互联网 发布:手机ai软件下载 编辑:程序博客网 时间:2024/06/11 07:23
Atlantis
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11823 Accepted Submission(s): 4990
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
题意:
求矩形面积的大小,重叠的部分只用计算一次即可
题解:
线段树+坐标离散化+扫描线+二分查找线段的左右端点
下面是转载他人的:
http://blog.csdn.net/u013480600/article/details/22548393 的解析
http://blog.csdn.net/xingyeyongheng/article/details/8927732 的代码
线段树的典型扫描线用法.
首先假设有下图两个矩阵,我们如果用扫描线的方法如何计算它们的总面积呢?
首先我们将矩形的上下边分为上位边(即y坐标大的那条平行于x轴的边),和下位边(y坐标小的平行于x轴的边).然后我们把所有矩形的上下位边按照他们y坐标从小到大排序,可以得到4条扫描线:
又因为上面2个矩形有4个不同的浮点数x坐标,所以我们需要把x坐标离散化,这样才能用线段树来维护信息.所以我们这样离散化:
由上图可知,4个不同的x坐标把x轴分成了3段有效的区间.这里要注意我们线段树中每个叶节点(控制区间[L,L])不是指X[L]坐标,而是指区间[X[L],X[L+1]].线段树中其他节点控制的区间[L,R],也是指的x坐标轴的第L个区间到第R个区间的范围,也就是X[L]到X[R+1]坐标的范围.
然后我们Y坐标从小到大的顺序读入每条扫描线,并维护当前我们所读入的所有扫描线能有效覆盖X轴的最大长度sum[1].这里特别要注意如果我们读入的扫描线是矩形的下位边,那么我们就使得该范围的标记cnt位+1,如果是上位边,那么该范围的cnt就-1.所以如果cnt=0时,表示该节点控制的范围没有被覆盖,只要cnt!=0 就表示该节点控制的几块区间仍然被覆盖.
下面依次读入每条矩阵边,来一一分析,首先是读入第一条矩阵边:
我们读入了矩形1的下位边,那么该区域的cnt就+1=1了,所以该区域[10,20]就被覆盖了,然后可以推出整个区域被覆盖的长度是10.再根据第二条扫描线离第一条扫描线的高度差为5.所以不管你第二条扫描线是哪个矩形的什么边,或者能覆盖到X轴的什么范围,我上图中蓝色的矩形面积肯定是要算到总面积里面去的.即总面积ret+=sum[1]*(扫描线2的高度-扫描线1的高度). (想想看是不是这样).
下面读第二条扫描线:
由于第二条扫描线也是下位边,所以[15,20]和[20,25]的cnt+1.使得我们覆盖的范围变成了[10,25]了,并且第3条扫描线在20高度,所以这次我们必然增加的面积是上面深蓝色的长条=sum[1]*(扫描线3的高度-扫描线2的高度).
下面我们要读第三条扫描线了:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int MAX=200+10;int mark[MAX<<2];///记录某个区间的下底边个数double sum[MAX<<2];///记录某个区间的下底边总长度double hashs[MAX];///对x进行离散化,否则x为浮点数且很大无法进行线段树///以横坐标作为线段(区间),对横坐标线段进行扫描///扫描的作用是每次更新下底边总长度和下底边个数,增加新面积struct seg ///线段{ double l,r,h; int d; seg() {} seg(double x1,double x2,double H,int c):l(x1),r(x2),h(H),d(c) {} bool operator<(const seg &a)const { return h<a.h; }} s[MAX];void Upfather(int n,int left,int right){ if(mark[n])sum[n]=hashs[right+1]-hashs[left];///表示该区间整个线段长度可以作为底边 else if(left == right)sum[n]=0;///叶子结点则底边长度为0(区间内线段长度为0) else sum[n]=sum[n<<1]+sum[n<<1|1];}void Update(int L,int R,int d,int n,int left,int right){ if(L<=left && right<=R) ///该区间是当前扫描线段的一部分,则该区间下底边总长以及上下底边个数差更新 { mark[n]+=d;///更新底边相差差个数 Upfather(n,left,right);///更新底边长 return; } int mid=(left+right)>>1; if(L<=mid)Update(L,R,d,n<<1,left,mid); if(R>mid)Update(L,R,d,n<<1|1,mid+1,right); Upfather(n,left,right);}int search(double key,double* x,int n){ int left=0,right=n-1; while(left<=right) { int mid=left+right>>1; if(x[mid] == key)return mid; if(x[mid]>key)right=mid-1; else left=mid+1; } return -1;}int main(){ int n,num=0; double x1,x2,y1,y2; freopen("in.txt","r",stdin); while(scanf("%d",&n)&&n) { int k=0; for(int i=0; i<n; ++i) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); hashs[k]=x1; s[k++]=seg(x1,x2,y1,1); hashs[k]=x2; s[k++]=seg(x1,x2,y2,-1); } ///从小到大排序 sort(hashs,hashs+k);///对扫描线的y坐标进行排序 sort(s,s+k); int m=1;///若有8个端点,则有7段,即七个叶子节点 for(int i=1; i<k; ++i) ///去重复端点 if(hashs[i] != hashs[i-1])hashs[m++]=hashs[i]; double ans=0; for(int i=0; i<k; ++i) ///扫描线段,二分查找此扫描线的左右端点 { int L=search(s[i].l,hashs,m); int R=search(s[i].r,hashs,m)-1; Update(L,R,s[i].d,1,0,m-1);///扫描线段时更新底边长度和底边相差个数 ans+=sum[1]*(s[i+1].h-s[i].h);///新增加面积 } printf("Test case #%d\nTotal explored area: %.2lf\n\n",++num,ans); } return 0;}
- hdu 线段树 (矩形面积并+离散化+二分查找)
- hdu 1542 Atlantis 线段树矩形面积并+离散化
- HDU 1542【线段树--矩形面积的并,扫描线+离散化】
- hdu 1542 Atlantis 线段树+矩形面积并+离散化点
- POJ1151 (HDU 1542) Atlantis【矩形面积并,线段树+离散化+扫描线模板】
- HDU 1542 Atlantis(矩形面积并,线段树+离散化+线扫描)
- HDU-1542/POJ-1151 Atlantis(矩形并面积--线段树+离散化)
- 线段树求矩形面积并 扫描线+离散化
- POJ1151Atlantis矩形面积并,线段树离散化
- 线段树求矩形面积并 扫描线+离散化
- hdu3265-Posters 线段树+离散化 求矩形面积并
- poj 1151 线段树+离散化+扫描线 矩形面积并 (矩阵操作类)
- poj 1151 Atlantis(矩形面积并,线段树+离散化)
- Codevs 题目3044 矩形面积求并(线段树+扫描线+离散化)
- HDU1542——Atlantis(扫描线,线段树,矩形面积并,离散化)
- POJ1151 Atlantis(线段树,扫描线,离散化,矩形面积并)
- HDU1542 POJ1151矩形面积合并(线段树+离散化)
- hdu1255 覆盖的面积(线段树+扫描线+离散化,求矩形面积并)
- 烂泥:redis3.2.3安装与配置
- 2017.1.20【初中部 】普及组模拟赛C组 鸡腿の游戏 题解
- NOI 2015 品酒大会
- 【16级第一周寒假作业B题】
- ARM之时钟体系
- hdu 线段树 (矩形面积并+离散化+二分查找)
- 细说vue的过渡动画
- View分发机制
- (转)量化策略:Ricequant迎新年50篇干货分享
- 51 NOD 1091 线段的重叠
- OpenJudge 2989 糖果
- CodeForces 444C - DZY Loves Colors(线段树)
- 树状数组(3)
- ORACLE中使用RAMA删除部分日志