首页 > 其他 > 详细

扫描线

时间:2019-11-10 16:02:39      阅读:89      评论:0      收藏:0      [点我收藏+]

Luogu

这道题机房大佬早就会了,而我现在才刚刚懂那么一点点。。。qwq

Code:

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 #define ls rt << 1
 4 #define rs rt << 1 | 1
 5 using namespace std;
 6 ll read() {
 7     ll re = 0, f = 1;
 8     char ch = getchar();
 9     while (ch < 0 || ch > 9) {if (ch == -) f = -f; ch = getchar();}
10     while (0 <= ch && ch <= 9) {re = re * 10 + ch - 0; ch = getchar();}
11     return re * f;
12 }
13 const int N = 1e5 + 5;
14 int n, xl, yl, xr, yr;
15 struct _line {
16     int l, r, h, f;
17 }line[N << 1];
18 bool cmp(_line a, _line b) {
19     return a.h < b.h;
20 }
21 int tag[N << 3], x[N << 3];
22 ll ans, len[N << 3];
23 void push_up(int rt, int l, int r) {
24     len[rt] = tag[rt] ? len[rt] : (l == r ? 0 : len[ls] + len[rs]);
25     //若不是0,说明被覆盖过了,就不变
26     //向上跟新的时候,如果tag[x]是0,说明还没有覆盖过,
27     //直接向上合并,其中最下方的单点没有长度,所以是0
28 }
29 void change(int rt, int l, int r, int L, int R, int d) {
30     if (L <= l && r <= R) {
31         len[rt] = (tag[rt] += d) ? x[r + 1] - x[l] : 0;
32         //若该节点修改后标记不为0,说明被覆盖过,要重新计算边并集长度
33         //若为0,则通过push_up进行直接合并len[ls] + len[rs]
34         push_up(rt, l, r);
35         return;
36     }
37     int mid = (l + r) / 2;
38     if (L <= mid) {
39         change(ls, l, mid, L, R, d);
40     }
41     if (R > mid) {
42         change(rs, mid + 1, r, L, R, d);
43     }
44     push_up(rt, l, r);
45 }
46 int main () {
47     n = read();
48     for (int i = 1; i <= n; i++) {
49         xl = read();
50         yl = read();
51         xr = read();
52         yr = read();
53         x[(i << 1) - 1] = xl;
54         x[i << 1] = xr;
55         line[(i << 1) - 1] = _line{xl, xr, yl, 1};//四元组表示一条边,1表示下边
56         line[i << 1] = _line{xl, xr, yr, -1};//-1表示上边
57     }
58     sort(x + 1, x + 1 + 2 * n);//排序x轴方便离散化
59     sort(line + 1, line + 1 + 2 * n, cmp);//按y排序
60     int m = unique(x + 1, x + 1 + 2 * n) - x - 2;
61     for (int i = 1; i <= 2 * n; i++) {
62         int xL = lower_bound(x + 1, x + 1 + m, line[i].l) - x;
63         int xR = lower_bound(x + 1, x + 1 + m, line[i].r) - x - 1;//-1 是因为防止出现一个没有长度的点代表区间的情况
64                                                         //所以区间[l,r]用[l,r+1]表示,那么修改的时候就修改[l,r-1]
65         ans += len[1] * (line[i].h - line[i - 1].h);//len[1]是我们关心的答案,而且每次都被更新
66         change(1, 1, m, xL, xR, line[i].f);//修改
67     }
68     printf("%lld\n", ans);
69     return 0;
70 }
View Code

 

 

扫描线

原文:https://www.cnblogs.com/Sundial/p/11830445.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!