求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树)
Posted -ackerman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树)相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/contest/332656#problem/J
思路:
这道题的大体的思路其实还是扫描线的思路。 就是我们要清晰之前我们所说的len 代表的是被覆盖了一次及以上次数的线段长度
为叙述方便,我们假设len[2]为当前线段被覆盖了两次的长度,len[1]为当前线段被覆盖了一次的长度,而len[0]就是这条线段的长度,并且满足len[2]+len[1]=len[0]。
首先,如果当前这条线段已经被覆盖了两次了,那么这条线段的len[2]就应该等于len[0],而len[1]就应该等于0。
其次,如果当前这条线段被覆盖了一次,那么这条线段的len[2]就应该是,左右子线段的len[2]的和加上左右子线段的len[1],当然,前提是当前线段不能是线段树中的叶子结点,否则它就没有左右子线段不是吗?这时候,当前线段的len[2]就应该等于0。而len[1]就等于len[0],最后要注意当前线段的len[1]要减去len[2],以满足len[1]+len[2]=len[0]。
最后,如果这条线段没有被覆盖过,并且当前线段不是线段树里的叶子结点,那么它的len[1]和len[2]都应该从它的左右子线段的len[1]和len[2]得到,如果是叶子结点,那么len[1]和len[2]都等0。
因为采用的是魔改的线段树 所以叶子结点需要多开一个标记
1 #include <math.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <iostream> 5 #include <algorithm> 6 #include <string> 7 #include <string.h> 8 #include <vector> 9 #include <map> 10 #include <stack> 11 #include <set> 12 #include <random> 13 14 #define LL long long 15 #define ls nod<<1 16 #define rs (nod<<1)+1 17 const int maxn = 2e5 + 10; 18 const double eps = 1e-9; 19 20 double v[maxn]; 21 22 struct L { 23 double x; 24 double y1,y2; 25 int state; 26 bool operator <(const L &ith) const{ 27 return x<ith.x; 28 } 29 }line[maxn]; 30 31 struct segment_tree { 32 double l,r; 33 int cover; 34 double len[3]; 35 bool flag; 36 void init() { 37 memset(len,0, sizeof(len)); 38 } 39 }tree[maxn<<3]; 40 41 void pushup(int nod) { 42 if (tree[nod].cover) { 43 tree[nod].len[0] = tree[nod].r - tree[nod].l; 44 } 45 else 46 tree[nod].len[0] = tree[ls].len[0] + tree[rs].len[0]; 47 48 if (tree[nod].cover >= 2) { 49 tree[nod].len[2] = tree[nod].len[0]; 50 tree[nod].len[1] = 0; 51 } 52 else if (tree[nod].cover == 1) { 53 if (tree[nod].flag) { 54 tree[nod].len[2] = 0; 55 } 56 else { 57 tree[nod].len[2] = (tree[ls].len[2] + tree[rs].len[2] + tree[ls].len[1] + tree[rs].len[1]); 58 } 59 tree[nod].len[1] = tree[nod].len[0]; 60 tree[nod].len[1] -= tree[nod].len[2]; 61 } 62 else { 63 if (tree[nod].flag) { 64 tree[nod].len[2] = tree[nod].len[1] = 0; 65 } 66 else { 67 tree[nod].len[2] = tree[ls].len[2] + tree[rs].len[2]; 68 tree[nod].len[1] = tree[ls].len[1] + tree[rs].len[1]; 69 } 70 } 71 } 72 73 void build(int l,int r,int nod=1) { 74 tree[nod].l = v[l]; 75 tree[nod].r = v[r]; 76 tree[nod].init(); 77 tree[nod].cover = 0; 78 tree[nod].flag = false; 79 if (r-l <= 1) { 80 tree[nod].flag = true; 81 return; 82 } 83 int mid = (l + r) >> 1; 84 build(l,mid,ls); 85 build(mid,r,rs); 86 } 87 88 void modify(double x,double y,int z,int nod=1) { 89 double l = tree[nod].l,r = tree[nod].r; 90 if (x <= l && y >= r){ 91 tree[nod].cover += z; 92 pushup(nod); 93 return ; 94 } 95 if (x < tree[ls].r) 96 modify(x,y,z,ls); 97 if (y > tree[rs].l) 98 modify(x,y,z,rs); 99 pushup(nod); 100 } 101 102 int main() { 103 int T; 104 scanf("%d",&T); 105 while (T--) { 106 int n; 107 double a, b, c, d; 108 scanf("%d",&n); 109 for (int i = 1; i <= n; i++) { 110 scanf("%lf%lf%lf%lf",&a,&b,&c,&d); 111 v[i] = b; 112 v[n + i] = d; 113 line[i].x = a; 114 line[i].y1 = b; 115 line[i].y2 = d; 116 line[i].state = 1; 117 line[i+n].x = c; 118 line[i+n].y1 = b; 119 line[i+n].y2 = d; 120 line[i+n].state = -1; 121 } 122 std::sort(v + 1, v + 1 + (n << 1)); 123 std::sort(line + 1, line + 1 + (n << 1)); 124 build(1, n << 1); 125 double ans = 0.0; 126 for (int i = 1; i <= 2 * n; i++) { 127 ans += tree[1].len[2] *(line[i].x - line[i-1].x); 128 //printf("%lf ",tree[1].len[2]); 129 modify(line[i].y1, line[i].y2, line[i].state); 130 } 131 printf("%.2lf ",ans); 132 } 133 return 0; 134 }
以上是关于求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树)的主要内容,如果未能解决你的问题,请参考以下文章