求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树)

题目链接: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 
  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 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\n",tree[1].len[2]);
129             modify(line[i].y1, line[i].y2, line[i].state);
130         }
131         printf("%.2lf\n",ans);
132     }
133     return 0;
134 }

 

你可能感兴趣的:(求出被矩形覆盖过至少两次的区域的面积(扫描线 + 线段树))