hdu 1542 & poj 1151 Atlantis 线段树扫描线求矩形面积并
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542
题意:给出n个矩形,求矩形面积并。
思路:经典的用扫描线法求矩形面积并。由于坐标很大,可以选择离散化横坐标或者离散化纵坐标。
如果离散化横坐标,记录每个矩形的上下两条线段的左起点,右起点和高度以及为上边或者下边。
选择从下往上扫描,那么把矩形的下边记录为1,把矩形的上边记录为-1。
把这些线段按高度h从小到大排序,然后从下开始往上扫描,每次遇到一条直线,如果是下边,在线段树相应区间+1。
如果是上边,在线段树相应区间-1。然后更新总区间被覆盖的长度,每次加上该长度*(当前扫描到的直线与下一条直线的高度差)。
画个图就比较清楚了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n; 4 #define maxn 210 5 #define lson l, m, rt<<1 6 #define rson m+1, r, rt<<1|1 7 struct Line 8 { 9 double l, r, h; 10 int mark; 11 }line[maxn]; 12 double a[maxn], b[maxn]; 13 map <int, double> mp; 14 int cnt; 15 bool cmp(Line l1, Line l2) 16 { 17 return l1.h < l2.h; 18 } 19 int sum[maxn<<2]; 20 double cover[maxn<<2]; 21 void pushup(int l, int r, int rt) 22 { 23 if(sum[rt]) cover[rt] = mp[r+1] - mp[l]; 24 else 25 { 26 if(r == l) cover[rt] = 0; 27 else cover[rt] = cover[rt<<1] + cover[rt<<1|1]; 28 } 29 } 30 void build(int l, int r, int rt) 31 { 32 cover[rt] = 0; sum[rt] = 0; 33 if(l == r) return; 34 int m = (l+r)>>1; 35 build(lson); 36 build(rson); 37 pushup(l, r, rt); 38 } 39 void update(int L, int R, int val, int l, int r, int rt) 40 { 41 if(L == l && R == r) 42 { 43 sum[rt] += val; 44 pushup(l, r, rt); 45 return; 46 } 47 int m = (l+r)>>1; 48 if(R <= m) update(L, R, val, lson); 49 else if(L > m) update(L, R, val, rson); 50 else 51 { 52 update(L, m, val, lson); 53 update(m+1, R, val, rson); 54 } 55 pushup(l, r, rt); 56 } 57 int main() 58 { 59 //freopen("in.txt", "r", stdin); 60 //freopen("out.txt", "w", stdout); 61 int cast = 0; 62 while(~scanf("%d", &n) && n) 63 { 64 cnt = 0; mp.clear(); 65 for(int i = 1; i <= n; i++) 66 { 67 double x1, y1, x2, y2; 68 scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); 69 a[cnt++] = x1; a[cnt++] = x2; 70 71 line[i*2-1].l = x1; line[i*2-1].r = x2; //下边 72 line[i*2-1].h = y1; line[i*2-1].mark = 1; 73 74 line[i*2].l = x1; line[i*2].r = x2; 75 line[i*2].h = y2; line[i*2].mark = -1; //上边 76 } 77 for(int i = 0; i < cnt; i++) b[i] = a[i]; 78 sort(a, a+cnt); 79 int precnt = cnt; 80 cnt = unique(a, a+cnt) - a; 81 82 for(int i = 0; i < precnt; i++) 83 { 84 mp[lower_bound(a, a+cnt, b[i]) - a + 1] = b[i]; 85 } 86 sort(line+1, line+1+2*n, cmp); 87 88 build(1, cnt, 1); 89 double ans = 0; 90 for(int i = 1; i <= 2*n; i++) 91 { 92 int ll = lower_bound(a, a+cnt, line[i].l) - a + 1; 93 int rr = lower_bound(a, a+cnt, line[i].r) - a + 1; 94 update(ll, rr-1, line[i].mark, 1, cnt, 1); 95 if(i != 2*n) ans += cover[1]*(line[i+1].h - line[i].h); 96 } 97 cast++; printf("Test case #%d\n", cast); 98 printf("Total explored area: %.2f\n\n", ans); 99 100 } 101 return 0; 102 }