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

题目链接: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\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 }

原文地址:https://www.cnblogs.com/-Ackerman/p/11734737.html

时间: 2024-10-07 06:11:53

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

HDU1255_覆盖的面积(扫描线/线段树+离散)

解题报告 题目传送门 题意: 求面积交. 思路: 不会呀. 只知道线段树应该维护覆盖数大于2的线段长度. 不会更新,看了别人写的理解的,太菜了. 用sum1和sum2分别来表示覆盖数为1的区间长度和覆盖数为2的区间长度. 更新时即要更新sum1也要更新sum2: 区间如果被覆盖 sum1为实际区间长度,如果覆盖一次,sum2为左右子树的sum1和,覆盖两次就为实际区间长度. 没有被覆盖就直接等于左右子树的和. #include <algorithm> #include <iostream

hdu(1255)——覆盖的面积(线段树求面积交)

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 虽说覆盖两次区域的面积,但是这道题实际上就是求矩形的面积交. 膜拜能够想出这种解法的神牛,竟然能把实际的东西用这么抽象的语言表示出来,实在是佩服,现在关于扫描线的题才做了几道,没有对其深刻理解,但是多练总可以理解的,奋斗吧!!ACMer!!我是永远不会服输的.加油! 下面还是附上题解,写的不够详细清楚还请多多见谅. 首先我想说我是看了别人的博客学了思路,然后按照别人的代码来模仿写的. 这里推荐:http://www.cnblogs.

HDU 1255 覆盖的面积(线段树扫描线求面积的交)

Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 注意:本题的输入数据较多,推荐使用scanf读入数据. Out

HDU 1255 覆盖的面积(线段树扫描线)

Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 注意:本题的输入数据较多,推荐使用scanf读入数据. Out

HUD 1255——覆盖的面积(线段树+面积并多次+离散化)

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3756    Accepted Submission(s): 1846 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数

poj-1151矩形面积并-线段树

title: poj-1151矩形面积并-线段树 date: 2018-10-30 22:35:11 tags: acm 刷题 categoties: ACM-线段树 概述 线段树问题里的另一个问题,,,矩形面积并,,,, 之前看lazy更新时看到下面这个的讲解,,,一大堆文字还有一大堆的图,,,,当时果断跳过,,, 今天花了一下午加一晚上的时间看了看这块知识,,,然后尝试自己写出代码,,,算是简单的了解一下这块,,, 题意 这道矩形面积并问题的大意是给很多个矩形,,矩形之间可能有交集,,,然后

hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> #include <algorithm> #define MAXN 110 #define LL ((rt<<1)+1) #define RR ((rt<<1)+2) using namespace std; int n; struct segment{ double l

HDU 1255 覆盖的面积 (扫描线 线段树 离散化)

题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了,因为虽然现在都不等于 2,但是之前的那个线段加上现在的已经覆盖2次了. 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include &

HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21978    Accepted Submission(s): 8714 Problem Description There are several anc