线段树扫描线求矩形面积并
1.HDU-1542 Atlantis
Problem Description
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don’t process it.
Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
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
题解:
一道裸的线段树+扫描线。题意是求所有矩形覆盖的总面积,易知问题的主要处理对象是多个矩形的重叠部分。(重叠部分面积只算一次)
暴力求解的复杂度肯定是不能忍受的,这时可以想到利用线段树log时间维护区间信息的特性,利用线段树来维护一维的长度,另一维排序后枚举来算出总面积。
这里主要运用到扫描线这一种方法。
我们用一个结构体Segment维护每条边(每个矩形的上下两条边)的左端点,右端点,高度和属于上下哪条边4个特性。
我们先把一维离散化后用线段树维护(这里线段树每个叶子节点代表横坐标排序后X[i]~X[i+1]这段长度,因此l,r分别对应所代表节点的X[i],统计的时候该节点长度就是X[l]~X[r+1]),
另一维利用扫描线从一端扫到另一端(这里从下往上)。
sum[o]维护这个节点在当前情况下的总长度,cnt[o]维护这个节点上下边的相对情况,每扫到一条下边,对应cnt[o]+1,扫到上边cnt[o]-1,易知任何情况cnt[o]>=0,
则当这个节点的左右儿子的cnt情况不一致时,我们令该节点cnt=-1,这时我们更新时不能把这段当整体考虑。
代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #define M(a, b) memset(a, b, sizeof(a)) 8 #define lson o<<1 9 #define rson o<<1|1 10 const int N = 200 + 5; 11 int cnt[N<<2], qL, qR, v; 12 double X[N], sum[N<<2]; 13 struct Segment { 14 double l, r, h; 15 int f; 16 Segment() {} 17 Segment(double l, double r, double h, int f): l(l), r(r), h(h), f(f) {} 18 bool operator < (const Segment &rhs) const { 19 return h < rhs.h; 20 } 21 }node[N]; 22 23 void pushdown(int o, int L, int R) { 24 if (~cnt[o]) { 25 int M = (L + R) >> 1; 26 cnt[lson] = cnt[rson] = cnt[o]; 27 sum[lson] = cnt[lson] ? X[M+1]-X[L] : 0; 28 sum[rson] = cnt[rson] ? X[R+1]-X[M+1] : 0; 29 } 30 } 31 32 void pushup(int o, int L, int R) { 33 if (~cnt[lson] || ~cnt[rson]) cnt[o] = -1; 34 else if (cnt[lson] != cnt[rson]) cnt[o] = -1; 35 else { 36 cnt[o] = cnt[lson]; 37 } 38 sum[o] = sum[lson] + sum[rson]; 39 } 40 41 void build(int o, int L, int R) { 42 if (L == R) {cnt[o] = 0; sum[o] = 0;} 43 else { 44 int M = (L + R) >> 1; 45 build(lson, L, M); 46 build(rson, M+1, R); 47 pushup(o, L, R); 48 } 49 } 50 51 void update(int o, int L, int R) { 52 if (qL <= L && R <= qR) { 53 if (~cnt[o]) { 54 cnt[o] += v; 55 sum[o] = cnt[o] ? X[R+1]-X[L] : 0; 56 return; 57 } 58 } 59 int M = (L + R) >> 1; 60 pushdown(o, L, R); 61 if (qL <= M) update(lson, L, M); 62 if (M < qR) update(rson, M+1, R); 63 pushup(o, L, R); 64 } 65 66 int bin(int L, int R, double key) { 67 while (L < R) { 68 int M = (L + R) >> 1; 69 if (X[M] == key) return M; 70 else if (X[M] < key) L = M + 1; 71 else R = M - 1; 72 } 73 return L; 74 } 75 76 int main() { 77 int T = 0, n; 78 while (scanf("%d", &n), n) { 79 double x1, x2, y1, y2; 80 int num = 0, nn = 0; 81 for (int i = 1; i <= n; ++i) { 82 scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); 83 X[++num] = x1; X[++num] = x2; 84 node[++nn] = Segment(x1, x2, y1, 1); 85 node[++nn] = Segment(x1, x2, y2, -1); 86 } 87 sort(X+1, X+1+num); sort(node+1, node+1+nn); 88 int k = 1; 89 for (int i = 2; i <= nn; ++i) 90 if (X[i] != X[i-1]) X[++k] = X[i]; 91 build(1, 1, k-1); 92 double ans = 0; 93 for (int i = 1; i < nn; ++i) { 94 qL = bin(1, k, node[i].l); 95 qR = bin(1, k, node[i].r)-1; 96 v = node[i].f; 97 if(qL <= qR) update(1, 1, k-1); 98 ans += sum[1] * (node[i+1].h-node[i].h); 99 } 100 printf("Test case #%d\n", ++T); 101 printf("Total explored area: %.2f\n\n", ans); 102 } 103 104 return 0; 105 }
2.POJ-1389 Area of Simple Polygon
跟上面一题是几乎一样的,我的写法略微不同,我更喜欢下面这种较为简洁的写法
代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define lson o<<1 7 #define rson o<<1|1 8 #define INF 0x3f3f3f3f 9 #define M(a, b) memset(a, b, sizeof(a)) 10 const int N = 2e3 + 5; 11 int cnt[N<<2], sum[N<<2], X[N], qL, qR, v; 12 struct Seg { 13 int l, r, h, f; 14 Seg() {} 15 Seg(int l, int r, int h, int f): l(l), r(r), h(h), f(f) {} 16 bool operator < (const Seg &rhs) const { 17 return h < rhs.h; 18 } 19 }node[N]; 20 21 void pushup(int o, int L, int R) { 22 if (cnt[o]) sum[o] = X[R+1] - X[L]; 23 else sum[o] = sum[lson] + sum[rson]; 24 } 25 26 void build(int o, int L, int R) { 27 cnt[o] = sum[o] = 0; 28 if (L == R) return; 29 else { 30 int M = (L + R) >> 1; 31 build(lson, L, M); 32 build(rson, M+1, R); 33 } 34 } 35 36 void update(int o, int L, int R) { 37 if (qL <= L && R <= qR) { 38 cnt[o] += v; 39 } 40 else { 41 int M = (L + R) >> 1; 42 if (qL <= M) update(lson, L, M); 43 if (M < qR) update(rson, M+1, R); 44 } 45 pushup(o, L, R); 46 } 47 48 int main() { 49 int x1, x2, y1, y2; 50 while (1) { 51 bool first = 1; 52 int n = 0, m = 0; 53 while (scanf("%d%d%d%d", &x1, &y1, &x2, &y2), x1 != -1) { 54 first = 0; 55 X[++n] = x1; X[++n] = x2; 56 node[++m] = Seg(x1, x2, y1, 1); 57 node[++m] = Seg(x1, x2, y2, -1); 58 } 59 if (first) break; 60 sort(X+1, X+1+n); sort(node+1, node+1+m); 61 int k = 1; 62 for (int i = 2; i <= n; ++i) 63 if (X[i] != X[i-1]) X[++k] = X[i]; 64 build(1, 1, k-1); 65 int ans = 0; 66 for (int i = 1; i < m; ++i) { 67 qL = lower_bound(X+1, X+1+k, node[i].l) - X; 68 qR = lower_bound(X+1, X+1+k, node[i].r) - X - 1; 69 v = node[i].f; 70 if (qL <= qR) update(1, 1, k-1); 71 ans += sum[1] * (node[i+1].h - node[i].h); 72 } 73 printf("%d\n", ans); 74 } 75 76 return 0; 77 }