线段树+扫描线求矩形面积的并
Posted df-yimeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树+扫描线求矩形面积的并相关的知识,希望对你有一定的参考价值。
POJ 1151 Atlantis(线段树+扫描线)
参考博客https://blog.csdn.net/lwt36/article/details/48908031
上面博客的原理讲解非常清楚
在这我只对代码的模板分层讲解
一些基础的
#include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #include <cmath> #define lson rt<<1,left,mid #define rson rt<<1|1,mid,right #define eps 1e-8 using namespace std; const int maxn = 222; //线段树 struct node{ double len; int cover; }tree[maxn << 2];
线段树中len 是覆盖标记的长度,也就是扫描线扫过后的所有覆盖的长度
//离散化 double X[maxn]; int N;
以上是离散化的数组,因为x是浮点值,所以先映射到一个数组里,然后排序————从小到大
再利用一下代码
sort(X,X+N); int tn = unique(X,X+N) - X;
build(1,0,tn-1);
得到不同x的离散范围
这样就可以建树了
struct edge{ double x1,x2,y; int flag; }e[maxn<<2]; bool cmp(edge a,edge b) { if(a.y != b.y)return a.y < b.y; else return a.flag > b.flag; } int cnt; void add(double x1,double x2,double y,double xx,int flag) { e[cnt].x1 = x1; e[cnt].x2 = x2; e[cnt].y = y; e[cnt].flag = flag; X[N++] = xx; cnt++; } void init() { cnt = 0; N = 0; }
以上是对边的存储,排序,加边,和整体的初始化操作
接下来我们建树:主要是初始化len和cover的值
void build(int rt,int left,int right) { tree[rt].len = 0.0; tree[rt].cover = 0; if(left + 1 == right)return; int mid = (left + right) >> 1; build(lson); build(rson); }
然后是扫描线更新,进本的更新,比较时利用离散化时的映射进行比较更新,找到区间更新cover,没有找到继续向下,知道叶子节点
中间顺便进行pushup向上维护
void updata(int rt,int left,int right,double x1,double x2,int v) { if(Equal(X[left],x1)&&Equal(X[right],x2)) { tree[rt].cover += v; } if(left + 1 < right) { int mid = (left + right) >> 1; if(x2 <= X[mid]+eps) updata(lson,x1,x2,v); else if(x1 >= X[mid] - eps) updata(rson,x1,x2,v); else { updata(lson,x1,X[mid],v); updata(rson,X[mid],x2,v); } } pup(rt,left,right); }
维护应该比较好懂
bool Equal(double x,double y) { return abs(x-y) <= eps; } void pup(int rt,int left,int right) { if(tree[rt].cover) tree[rt].len = X[right] - X[left]; else if(left + 1 == right) tree[rt].len = 0.0; else tree[rt].len = tree[rt<<1].len + tree[rt<<1|1].len; }
到此就差不多了
int main() { int cas = 1; int n; double x1,y1,x2,y2; while(~scanf("%d",&n),n) { init(); for(int i = 1;i <= n;++i) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); add(x1,x2,y1,x1,1); add(x1,x2,y2,x2,0); } sort(e,e+cnt,cmp); //从小到大的离散化,把值都映射到了1 - N sort(X,X+N); int tn = unique(X,X+N) - X; build(1,0,tn-1); double ans = 0.0; double length = 0.0; for(int i = 0;i < cnt;i++) { if(e[i].flag == 1) updata(1,0,tn-1,e[i].x1,e[i].x2,1); else updata(1,0,tn-1,e[i].x1,e[i].x2,-1); if(i != 0) ans += length * (e[i].y - e[i-1].y); length = tree[1].len; } printf("Test case #%d ",cas++); printf("Total explored area: %.2f ",ans); } return 0; }
以上是关于线段树+扫描线求矩形面积的并的主要内容,如果未能解决你的问题,请参考以下文章
HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)