HDU - 1255 扫描线+离散化进阶
这道题最开始我以为和HDU - 1542 那道题一样,只需要把cover次数改成2次即可,但是后面仔细一想,我们需要求的是覆盖次数大于等于2次的,这样的话,我们需要维护两个长度,HDU-1542 由于求的是覆盖次数大于等于一次的,我们只需要维护一个覆盖次数大于等于1的长度的len1就行,但是这道题我们要求的是覆盖两次以及两次以上的长度,这样乘以高度差,才是面积。
现在我们来想如何维护这个值?
给线段树打个标记cover,代表这个区间被完全覆盖的次数。
我们先来看看,维护覆盖一次及其以上的,应该怎么实现,我们可以从中得到启示。
- cover不为0 那么这个区间被完全覆盖。我们把整个区间长度给len1,但是我们由于经过离散化。表达式为:tree[root].len1=pos[r+1]-pos[l]
- L==R 代表跑到了叶子节点,不会有节点信息往上传,因此赋0
- 不满足上述两者,我们就可以认为,父节点的信息,又两个儿子节点的提供。
那么覆盖两次的呢?同样的分情况讨论
- cover>1 那么这个区间内被完全覆盖至少2次,值等于区间长度。
- L==R 同样的信息不能由子节点提供,赋0。
- Cover==1 那么这个区间被完全覆盖至少一,子节点覆盖次数大于等于1的次数往上pushup后,变成至少两次。
- 反之节点信息由两个子节点提供
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
inline int L(int r)
{
return r<<;
};
inline int R(int r)
{
return r<<|;
};
inline int MID(int l,int r)
{
return (l+r)>>;
};
const int maxx = ;
struct Line
{
double l,r,h;
int f;
}line[maxx*];
struct node
{
int l,r,cover;
double len1,len2;
} tree[maxx<<];
double pos[maxx];
bool cmp(Line a,Line b){
return a.h<b.h;
}
void buildtree(int root,int l,int r)//建树
{
tree[root].l=l;
tree[root].r=r;
tree[root].len1=;
tree[root].len2=;
tree[root].cover=;
if (l==r)
{
return;
}
int mid = MID(l,r);
buildtree(L(root),l,mid);
buildtree(R(root),mid+,r);
}
int bin(double key,int low,int high)
{
while(low<=high)
{
int mid = (low+high)>>;
if (pos[mid] == key)
return mid;
else if (pos[mid] < key)
low = mid+;
else
high = mid-;
}
return -;
}
void pushup(int root)
{
int l=tree[root].l;
int r=tree[root].r;
if (tree[root].cover)tree[root].len1=pos[r+]-pos[l];
else if (l==r)tree[root].len1=;
else tree[root].len1=tree[L(root)].len1+tree[R(root)].len1; if (tree[root].cover>)tree[root].len2=tree[root].len1;
else if (l==r)tree[root].len2=;
else if (tree[root].cover==)tree[root].len2=tree[L(root)].len1+tree[R(root)].len1;
else tree[root].len2=tree[L(root)].len2+tree[R(root)].len2;
}
void update(int root,int ul,int ur,int c)
{
int l=tree[root].l;
int r=tree[root].r;
if (ul<=l && r<=ur)
{
tree[root].cover+=c;
pushup(root);
return;
}
int mid=MID(l,r);
if (ur<=mid)update(L(root),ul,ur,c);
else if (ul>mid)update(R(root),ul,ur,c);
else {
update(L(root),ul,mid,c);
update(R(root),mid+,ur,c);
}
pushup(root);
}
int main()
{
int t;
scanf("%d",&t);
int n;
while(t--){
int nums=;
scanf("%d",&n);
for (int i=;i<n;i++){
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[nums].l=x1;
line[nums].r=x2;
line[nums].h=y1;
line[nums].f=;
pos[nums++]=x1;
line[nums].l=x1;
line[nums].r=x2;
line[nums].h=y2;
line[nums].f=-;
pos[nums++]=x2;
}
sort(pos,pos+nums);
sort(line,line+nums,cmp);
int m=;
for (int i=;i<nums;i++)//去重
if (pos[i]!=pos[i-])
pos[m++]=pos[i];
buildtree(,,m-);
double ans=;
for (int i=;i<nums;i++)
{
int l=bin(line[i].l,,m-);
int r=bin(line[i].r,,m-)-;
update(,l,r,line[i].f);
ans+=tree[].len2*(line[i+].h-line[i].h);
}
printf("%.2lf\n",ans);
}
return ;
}
HDU - 1255 扫描线+离散化进阶的更多相关文章
- HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)
链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...
- 线段树扫描线(一、Atlantis HDU - 1542(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))
扫描线求周长: hdu1828 Picture(线段树+扫描线+矩形周长) 参考链接:https://blog.csdn.net/konghhhhh/java/article/details/7823 ...
- 扫描线三巨头 hdu1928&&hdu 1255 && hdu 1542 [POJ 1151]
学习链接:http://blog.csdn.net/lwt36/article/details/48908031 学习扫描线主要学习的是一种扫描的思想,后期可以求解很多问题. 扫描线求矩形周长并 hd ...
- HDU 1255 覆盖的面积(线段树+扫描线)
题目地址:HDU 1255 这题跟面积并的方法非常像,仅仅只是须要再加一个变量. 刚開始我以为直接用那个变量即可,仅仅只是推断是否大于0改成推断是否大于1.可是后来发现了个问题,由于这个没有下放,没延 ...
- hdu 1255 覆盖的面积(线段树 面积 交) (待整理)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. In ...
- hdu1542 Atlantis (线段树+扫描线+离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu 1255 覆盖的面积(求覆盖至少两次以上的面积)
了校赛,还有什么途径可以申请加入ACM校队? 覆盖的面积 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- HDU 1255 覆盖的面积 (线段树+扫描线+离散化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 题意很清楚,就是让你求矩阵之间叠加层数大于1的矩形块的面积和. 因为n只有1000,所以我离散化 ...
- 覆盖的面积 HDU - 1255 线段树+扫描线+离散化 求特定交叉面积
#include<cstdio> #include<map> #include<algorithm> using namespace std; ; struct N ...
随机推荐
- 数据库之mysql篇(2)—— mysql常识引入/用户授权
常识引入 1.概念: 数据库:本质上是一个文件夹 1)查看本机所有数据库:show databases; 结束符:分号[:],一切数据行的结尾都以分号作为结束 2)创建数据库:create 数据库名 ...
- Sqlserver分区表
1. 分区表简介 分区表在逻辑上是一个表,而物理上是多个表.从用户角度来看,分区表和普通表是一样的.使用分区表的主要目的是为改善大型表以及具有多个访问模式的表的可伸缩性和可管理性. 分区表是把数据按设 ...
- 力扣算法题—051N皇后问题
#include "000库函数.h" //使用回溯法来计算 //经典解法为回溯递归,一层一层的向下扫描,需要用到一个pos数组, //其中pos[i]表示第i行皇后的位置,初始化 ...
- Word中的通配符随意组合进行批量替换或删除某些内容
长文档需要批量修改或删除某些内容的时候,我们可以利用Word中的通配符来搞定这一切,当然,前提是你必须会使用它.通配符的功能非常强大,能够随意组合替换或删除我们定义的规则内容,下面易老师就分享一些关于 ...
- centos7下kubernetes(6。kubernetes创建资源的两种方式)
两种方式:1.命令:2.配置文件 之前我们在部署K8S的时候分别用到了命令和配置文件创建K8s资源: 1.命令方式:kubectl run nginx-deployment --image=nginx ...
- 创建线程时如果既传入了runnable对象,又继承thread重写了run方法,会执行的哪里的代码
1 使用线程的方式,继承thread类,重写run方法 new Thread() { @Override public void run() { System.out.println("我是 ...
- 【适合N卡独显电脑的环境配置】Tensorflow教程-Windows 10下安装tensorflow 1.5.0 GPU with Anaconda
注意: 1.目前Anaconda 更新原命令activate tensorflow 改为 conda activate tensorflow 2. 目前windows with anaconda 可以 ...
- SpringBoot实现JWT保护前后端分离RESTful API
通常情况下, 将api直接暴露出来是非常危险的. 每一个api呼叫, 用户都应该附上额外的信息, 以供我们认证和授权. 而JWT是一种既能满足这样需求, 而又简单安全便捷的方法. 前端login获取J ...
- PHP 2 语句 数据类型 字符串函数 常量
在 PHP 中,有两种基本的输出方法:echo 和 print. 在本教程中,我们几乎在每个例子中都会用到 echo 和 print.因此,本节为您讲解更多关于这两条输出语句的知识. PHP echo ...
- RabbitMQ学习系列
http://www.cnblogs.com/zhangweizhong/category/855479.html https://www.cnblogs.com/zhangweizhong/p/56 ...