-
M - Atlantis
- HDU - 1542
- 感谢:https://www.cnblogs.com/scau20110726/archive/2013/03/21/2972808.html
- 1.矩形比较多,坐标也很大,所以横坐标需要离散化(纵坐标不需要),熟悉离散化后这个步骤不难,所以这里不详细讲解了,不明白的还请百度
- 2.重点:扫描线法:假想有一条扫描线,从左往右(从右往左),或者从下往上(从上往下)扫描过整个多边形(或者说畸形。。多个矩形叠加后的那个图形)。如果是竖直方向上扫描,则是离散化横坐标,如果是水平方向上扫描,则是离散化纵坐标。下面的分析都是离散化横坐标的,并且从下往上扫描的。
- 扫描之前还需要做一个工作,就是保存好所有矩形的上下边,并且按照它们所处的高度进行排序,另外如果是上边我们给他一个值-1,下边给他一个值1,我们用一个结构体来保存所有的上下边
- 接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),这个投影对应的其实是个插入和删除线段操作。还记得给他们赋的值1或-1吗,下边是1,扫描到下边的话相当于往总区间插入一条线段,上边-1,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,对应的那一段的值都要增1,扫描到上边对应的那一段的值都要减1,如果总区间某一段的值为0,说明其实没有线段覆盖到它,为正数则有,那会不会为负数呢?是不可能的,可以自己思考一下)。
- 每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积
- (这个过程其实一点都不难,只是看文字较难体会,建议纸上画图,一画即可明白,下面献上一图希望有帮组)
- 注意线段树节点维护的是(i——i+1)一小线段为节点
-
#include<bits/stdc++.h> using namespace std; const int maxn = 210; struct edg { double l,r,h; int flag; bool operator<(const edg &b)const { return h<b.h; } } edge[maxn*2]; struct node { int l,r,lazy; double len; } tree[maxn*4]; double ls[maxn*2],ans; int cnt,n,NUM,nums; void add(double x1,double x2,double y,int id) { edge[cnt].flag=id; edge[cnt].h=y; edge[cnt].l=x1; edge[cnt++].r=x2; } void build(int root,int l,int r) { tree[root].l=l; tree[root].r=r; tree[root].len=0; tree[root].lazy=0; if(l==r)return ; int mid=(l+r)/2; build(root*2,l,mid); build(root*2+1,mid+1,r); } void pushup(int root) { if(tree[root].lazy) tree[root].len=ls[tree[root].r+1]-ls[tree[root].l]; else if(tree[root].l==tree[root].r) tree[root].len=0; else tree[root].len=tree[root*2].len+tree[root*2+1].len; } void updata(int root,int l,int r,int val) { if(tree[root].l==l&&tree[root].r==r) { tree[root].lazy+=val; pushup(root); return ; } int mid=(tree[root].l+tree[root].r)/2; if(l>mid) updata(root*2+1,l,r,val); else if(mid>=r) updata(root*2,l,r,val); else { updata(root*2,l,mid,val); updata(root*2+1,mid+1,r,val); } pushup(root); } int main() { while(scanf("%d", &n)) { if(n==0)break; ans=cnt=nums=0; for(int i=0; i<n; i++) { double x1,y,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y,&x2,&y2); add(x1,x2,y,1); add(x1,x2,y2,-1); ls[nums++]=x1; ls[nums++]=x2; } sort(edge,edge+cnt); sort(ls,ls+nums); int m=unique(ls,ls+nums)-ls; build(1,0, m-1); for(int i=0; i<cnt-1; i++) { int l=lower_bound(ls,ls+m,edge[i].l)-ls; int r=lower_bound(ls,ls+m,edge[i].r)-ls; updata(1,l,r-1,edge[i].flag); ans+=(edge[i+1].h-edge[i].h)*tree[1].len; } printf("Test case #%d\n", ++NUM); printf("Total explored area: %.2f\n\n", ans); } return 0; }
M - Atlantis HDU - 1542 -扫描线-面积并
最新推荐文章于 2022-05-18 06:00:00 发布