555搞了这么久算法居然才学扫描线......
愧疚愧疚
扫描线也不算是一种算法,实际上是一种技♂巧。
在处理矩形覆盖类的问题(目前只做了矩形覆盖hhh)时,我们将每个矩形的上下两条底边存储,记录左、右的坐标以及它距离x轴的高度h,同时定义一个标记tag为1/-1来表明它是上底边还是下底边。
与此同时也要存储线段的两个端点的横坐标于一个数组内,用于离散化。
随后我们去枚举每一条线段,采用离散化获得的下标进行线段树上的处理。
线段树中的节点存储一个cnt,用来判断求出当前节点的有效长度len。
1.如果cnt不为0,则len为当前区间的总长。
2.如果当前节点的l,r相等,则区间长度为0,毕竟是同一个点嘛。
3.不属于1/2的情况,则len取子节点len之和
然后我们发现,当合并区间[a, b]与[b + 1, c]时,我们少计算了[b, b + 1]这一小段间距。
所以在1中,我们求长度必须取X[r + 1] - X[l]才可以。
相对应的,在离散化取总的l与r时,r取r - 1,就恰好抵消啦!超棒哒!
当我们获得了这个len,只需要取得下一条线段与当前线段的高度h之差,二者的乘积就形成了一小块有效面积。
芜湖
如果题目给定的点是左上&右下,记得转化一下,两个swap即可。
1 #include<iostream>
2 #include<algorithm>
3 #include<cstring>
4 #include<string>
5 #include<cmath>
6 #define rg register
7 using namespace std;
8
9 const int N = 110;
10
11 struct seg
12 {
13 double l, r, h;
14 int tag;//1-下底边 0-上底边
15 seg(){}
16 seg(double ll, double rr, double hh, int tagg){
17 l = ll, r = rr, h = hh, tag = tagg;
18 }
19 bool operator < (const seg &i)const{
20 return h < i.h;
21 }
22 }e[N << 1];
23
24 struct node
25 {
26 int cnt;
27 double len;
28 node(){}
29 node(int cntt, int lenn){
30 cnt = cntt, len = lenn;
31 }
32 }t[N << 3];
33
34 double X[N << 1];
35
36 inline void push_up(int root, int l, int r)
37 {
38 if(t[root].cnt){
39 t[root].len = X[r + 1] - X[l];//合并时必须保证连续,r取多1
40 }else if(l == r){
41 t[root].len = 0;
42 }else{
43 t[root].len = t[root << 1].len + t[root << 1 | 1].len;
44 }
45 }
46
47 inline void upd(int L, int R, int l, int r, int root, int tag)
48 {
49 if(r < L || l > R) return ;
50 if(l >= L && r <= R){
51 t[root].cnt += tag;
52 push_up(root, l, r);
53 return ;
54 }
55 int mid = (l + r) >> 1;
56 upd(L, R, l, mid, root << 1, tag);
57 upd(L, R, mid + 1, r, root << 1 | 1, tag);
58 push_up(root, l, r);
59 }
60
61 int main(){
62 int n, cas = 1;
63 while(~scanf("%d",&n)){
64 if(n == 0) break;
65 for(rg int i = 0 ; i <= n ; i++){
66 t[i].cnt = t[i].len = 0;
67 }
68 int tot = 0;
69 double a, b, c, d;
70 for(rg int i = 1 ; i <= n ; i++){
71 scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
72 e[++tot] = seg(a, c, b, 1);
73 X[tot] = a;
74 e[++tot] = seg(a, c, d, -1);
75 X[tot] = c;
76 }
77 sort(X + 1, X + tot + 1);
78 sort(e + 1, e + tot + 1);
79 int m = unique(X + 1, X + tot + 1) - X - 1;
80 double res = 0;
81 for(int i = 1 ; i <= tot ; i++){
82 int l = lower_bound(X + 1, X + m + 1, e[i].l) - X;
83 int r = lower_bound(X + 1, X + m + 1, e[i].r) - X - 1;
84 //此处r少取一位,因为区间合并右端结果超出1,二者抵消
85 upd(l, r, 1, m, 1, e[i].tag);//
86 res += t[1].len * (e[i + 1].h - e[i].h);
87 }
88 printf("Test case #%d
", cas++);
89 printf("Total explored area: %.2f
", res);
90 }
91
92 return 0;
93 }
ps:本随笔系原创作品,欢迎转载,请在文末注明原文链接