hdu1542 Atlantis(矩形面积并+扫描线)
来源:互联网 发布:跨三层取mac 编辑:程序博客网 时间:2024/05/22 00:42
http://acm.hdu.edu.cn/showproblem.php?pid=1542
题意:给你n个矩形,求他们的面积并。
思路:看了两篇比较好的博客,推荐下第一个、第二个。求面积时要想用扫描线,首先要确定水平还是竖直方向。这里是从下往上扫描,由于横坐标较大所以对其离散化。离散化还是保存排序去重的步骤,重点是对这里扫描的理解。必须要注意的是,扫描线是可变的。提前用seg结构体数组将每条线段的左端点、右端点、高保存起来,然后用f保存其边的属性1为下边,-1为上边。每次求面积就必须要求边的长度,这里通过判断边的属性来给长度赋值。属性为1相当于插入一条边,属性为-1相当于删除一条边。求线段长度时如果cnt>0则说明区间被完全覆盖,长度直接算出;若cnt=0则说明没有被完全覆盖,由其左右儿子区间覆盖长度算出。
这题还有一点需注意,一旦将线段投影入线段树内,二分查找后即被拆分,中间的缺口会使区间长度减一,解决方法是前闭后开,推荐博客:第三个
最后,扫描线通常是扫描到一条,即求出其上面部分的面积,当扫描到最后一条线时,cnt为0,此时最后的更新长度的最底层区间长度无法更新即为0,up上来就是一连串0,长度即为0,细心模拟下就能发现。
这题学到了好多,感觉我没说清楚,还是看大牛的博客吧= =
#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <iostream>using namespace std;typedef long long LL;const int N = 50010;const int INF = 1e8;struct line{ int l, r; int cnt; double len;}tree[4*N];struct node{ double l, r, h; int f; bool operator < (const struct node & tmp) const { return h < tmp.h; }}seg[4*N];double x[N];void build(int i, int l, int r){ tree[i].l = l; tree[i].r = r; tree[i].len = 0; tree[i].cnt = 0; if(l == r) { return; } int mid = (l+r) >> 1; build(i*2, l, mid); build(i*2+1, mid+1, r);}int binsearch(double key, int k){ int high = k; int low = 1; while(high >= low) { int mid = (high+low) >> 1; if(x[mid] == key) { return mid; } else if(x[mid] < key) { low = mid+1; } else high = mid-1; } return -1;}void getlen(int i){ if(tree[i].cnt) { tree[i].len = x[tree[i].r+1]-x[tree[i].l]; return; } if(tree[i].l == tree[i].r) { tree[i].len = 0; return; } tree[i].len = tree[i*2].len+tree[i*2+1].len;}void update(int i, int l, int r, int f){ if(tree[i].l == l && tree[i].r == r) { tree[i].cnt += f; getlen(i); return; } int mid = (tree[i].l+tree[i].r) >> 1; if(mid >= r) update(i*2, l, r, f); else if(mid < l) update(i*2+1, l, r, f); else { update(i*2, l, mid, f); update(i*2+1, mid+1, r, f); } getlen(i);}int main(){ // freopen("in.txt", "r", stdin); int n, Case = 1; double x1, y1, x2, y2; while(~scanf("%d", &n)) { if(n == 0) break; int num = 1; for(int i = 1; i <= n; i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); seg[num].l = x1; seg[num].r = x2; seg[num].h = y1; seg[num].f = 1; x[num++] = x1; seg[num].l = x1; seg[num].r = x2; seg[num].h = y2; seg[num].f = -1; x[num++] = x2; } sort(seg+1, seg+num); sort(x+1, x+num); int k = 1; for(int i = 2; i < num; i++) { if(x[i-1] != x[i]) { x[++k] = x[i]; } } build(1, 1, k); double ans = 0; for(int i = 1; i < num; i++) { int l = binsearch(seg[i].l, k); int r = binsearch(seg[i].r, k)-1; // printf("%d %d\n", l, r); update(1, l, r, seg[i].f); ans += (seg[i+1].h-seg[i].h)*tree[1].len; } printf("Test case #%d\n", Case++); printf("Total explored area: %.2lf\n", ans); printf("\n"); } return 0;}
下面贴一下别人的图,相当于这个过程的模拟,注意下标数字的变化。
0 0
- HDU1542 Atlantis 扫描线 矩形面积并
- HDU1542 Atlantis(扫描线+矩形面积并+线段树)
- hdu1542 Atlantis(矩形面积并+扫描线)
- hdu1542 Atlantis(扫描线+矩形面积并)
- HDU1542——Atlantis(扫描线,线段树,矩形面积并,离散化)
- hdu1542 Atlantis(矩形面积并)
- 面积并---扫描线 hdu1542 Atlantis
- HDU1542 线扫描求矩形面积并
- 【HDU1542】Atlantis【线段树】【矩形面积并】
- hdu1542 Atlantis【矩形面积并+线段树】
- hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积
- HDU1542-Atlantis(线段树+扫描线——面积并)
- HDU1542 Atlantis(面积并)
- hdu1542 线段树扫描线求矩形面积的并
- poj1151 hdu1542 wikioi3044 Atlantis 矩形面积求并
- HDU-1542 Atlantis 矩形面积并 扫描线
- HDU 1542 —— Atlantis 【矩形面积并:扫描线】
- 【poj1151】Atlantis(矩形面积并+线段树+扫描线)
- WebService创建常见报错与解决
- Valid Anagram(easy)
- C/C++ typedef用法
- 跟着郝斌学数据结构(01)——预备
- 华为OJ——字符串反转
- hdu1542 Atlantis(矩形面积并+扫描线)
- cgroup
- 阳阳买苹果--C实现
- 递归算法详解
- 华为OJ——句子逆序
- mysql alter操作
- Oracle/Hive/Impala SQL比较(1-2)
- 棋盘覆盖问题
- Beautiful numbers