求解矩形覆盖面积 (线段树 + 扫描线)

扫描线算法流程:

1、想象一下有一条平行于y轴的直线,正在从左边缓缓向右平移……
2、再想像一下y轴上有一棵线段树,它记录的是y轴上每个点的覆盖次数
3、每当遇到某个矩形的某一条边时,就计算面积——用这次碰边的x坐标减去上一次碰边时的x坐标,再用这个差值乘以当前y轴上有多少个点被覆盖
4、当这条直线遇到某个矩形的左边时,将这个矩形的左边所对应的y轴区间的覆盖次数+1,当遇到某个矩形的右边时,就相应的-1
5、让这条线继续向右移动……

 

然后我的这个板子不采取离散化的原因是因为我魔改了线段树,普通的线段树是维护的连续的点,而我的这个线段树维护的是真正的“线段”

 

板子题:https://www.luogu.org/problem/P5490

 

 1 #include 
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 #include <string>
 7 #include <string.h>
 8 #include 
 9 #include 
10 #include 
11 #include <set>
12 #include 
13 
14 #define LL long long
15 #define ls nod<<1
16 #define rs (nod<<1)+1
17 const int maxn = 2e5 + 10;
18 
19 int v[maxn];
20 
21 struct L {
22     int x;
23     int y1,y2;
24     int state;
25     bool operator <(const L &ith) const{
26         return x<ith.x;
27     }
28 }line[maxn];
29 
30 struct segment_tree {
31     int l,r;
32     int cover;
33     LL len;
34 }tree[maxn<<3];
35 
36 void pushup(int nod) {
37     if (tree[nod].cover) {
38         tree[nod].len = (tree[nod].r - tree[nod].l);
39     }
40     else {
41         tree[nod].len = (tree[ls].len + tree[rs].len);
42     }
43 }
44 
45 void build(int l,int r,int nod=1) {
46     tree[nod].l = v[l];
47     tree[nod].r = v[r];
48     if (r-l <= 1)
49         return ;
50     int mid = (l + r) >> 1;
51     build(l,mid,ls);
52     build(mid,r,rs);
53 }
54 
55 void modify(int x,int y,int z,int nod=1) {
56     int l = tree[nod].l,r = tree[nod].r;
57     if (x <= l && y >= r){
58         tree[nod].cover += z;
59         pushup(nod);
60         return ;
61     }
62     if (x < tree[ls].r)
63         modify(x,y,z,ls);
64     if (y > tree[rs].l)
65         modify(x,y,z,rs);
66     pushup(nod);
67 }
68 
69 int main() {
70     int n;
71     int a,b,c,d;
72     scanf("%d",&n);
73     for (int i=1;i<=n;i++) {
74         scanf("%d%d%d%d",&a,&b,&c,&d);
75         v[i] = b;
76         v[n+i] = d;
77         line[i] = (L){a,b,d,1};
78         line[i+n] = (L){c,b,d,-1};
79     }
80     std::sort(v+1,v+1+(n<<1));
81     std::sort(line+1,line+1+(n<<1));
82     build(1,n<<1);
83     unsigned long long ans = 0;
84     for (int i=1;i<=2*n;i++) {
85         ans += tree[1].len*(line[i].x-line[i-1].x);
86         modify(line[i].y1,line[i].y2,line[i].state);
87     }
88     std::cout << ans << std::endl;
89     return 0;
90 }

 

 

板子题:

https://vjudge.net/contest/332656#problem/K

题意:

二维平面有n个平行于坐标轴的矩形,现在要求出这些矩形的总面积. 重叠部分只能算一次.

 

  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include <string>
  7 #include <string.h>
  8 #include 
  9 #include 
 10 #include 
 11 #include <set>
 12 #include 
 13 
 14 #define LL long long
 15 #define ls nod<<1
 16 #define rs (nod<<1)+1
 17 const int maxn = 2e5 + 10;
 18 
 19 double v[maxn];
 20 
 21 struct L {
 22     double x;
 23     double y1,y2;
 24     int state;
 25     bool operator <(const L &ith) const{
 26         return x<ith.x;
 27     }
 28 }line[maxn];
 29 
 30 struct segment_tree {
 31     double l,r;
 32     int cover;
 33     double len;
 34 }tree[maxn<<3];
 35 
 36 void pushup(int nod) {
 37     if (tree[nod].cover) {
 38         tree[nod].len = (tree[nod].r - tree[nod].l);
 39     }
 40     else {
 41         tree[nod].len = (tree[ls].len + tree[rs].len);
 42     }
 43 }
 44 
 45 void build(int l,int r,int nod=1) {
 46     tree[nod].l = v[l];
 47     tree[nod].r = v[r];
 48     if (r-l <= 1)
 49         return ;
 50     int mid = (l + r) >> 1;
 51     build(l,mid,ls);
 52     build(mid,r,rs);
 53 }
 54 
 55 void modify(double x,double y,int z,int nod=1) {
 56     double l = tree[nod].l,r = tree[nod].r;
 57     if (x <= l && y >= r){
 58         tree[nod].cover += z;
 59         pushup(nod);
 60         return ;
 61     }
 62     if (x < tree[ls].r)
 63         modify(x,y,z,ls);
 64     if (y > tree[rs].l)
 65         modify(x,y,z,rs);
 66     pushup(nod);
 67 }
 68 
 69 int main() {
 70     int n;
 71     double a,b,c,d;
 72     int t = 1;
 73     while(~scanf("%d",&n)) {
 74         if (n == 0)
 75             break;
 76         printf("Test case #%d\n",t++);
 77         for (int i = 1; i <= n; i++) {
 78             scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
 79             v[i] = b;
 80             v[n + i] = d;
 81             line[i].x = a;
 82             line[i].y1 = b;
 83             line[i].y2 = d;
 84             line[i].state = 1;
 85             line[i+n].x = c;
 86             line[i+n].y1 = b;
 87             line[i+n].y2 = d;
 88             line[i+n].state = -1;
 89         }
 90         std::sort(v + 1, v + 1 + (n << 1));
 91         std::sort(line + 1, line + 1 + (n << 1));
 92         build(1, n << 1);
 93         double ans = 0;
 94         for (int i = 1; i <= 2 * n; i++) {
 95             ans += tree[1].len * (line[i].x - line[i - 1].x);
 96             modify(line[i].y1, line[i].y2, line[i].state);
 97         }
 98         printf("Total explored area: %.2lf\n\n",ans);
 99     }
100     return 0;
101 }

 

你可能感兴趣的:(求解矩形覆盖面积 (线段树 + 扫描线))