poj1151 扫描线~

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\n", cas++);
89         printf("Total explored area: %.2f\n\n", res);        
90     }
91     
92     return 0;
93 }

ps:本随笔系原创作品,欢迎转载,请在文末注明原文链接

posted @ 2021-01-06 22:32  LegendN  阅读(88)  评论(0编辑  收藏  举报