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 ...
随机推荐
- C#-循环语句(六)
for循环 格式: for(表达式1;循环条件;表达式2) { 循环体; } 解释:先执行表达式1,再判断循环条件是否为真,如果为真则执行循环体,执行完成后再执行表达式2 再次判断循环条件,由此一直反 ...
- 洗礼灵魂,修炼python(89)-- 知识拾遗篇 —— 进程
进程 1.含义:计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位.说白了就是一个程序的执行实例. 执行一个程序就是一个进程,比如你打开浏览器看到我的博客,浏览器本身是一 ...
- 批量配置SSH互信脚本
在大规模自动化部署时我们常常需要配置好服务器的SSH互信,以便自动化脚本可以免密登录远程服务器,常规的手动配置SSH互信步骤如下: 使用ssh-keygen生成本地ssh key(mha01),生成的 ...
- c函数指针
#include <stdio.h> int max(int a, int b){ return a > b ? a : b; } int min(int a, int b){ re ...
- Objective-C简介
1.OC简介 全称:Objective-C,是扩充C的面向对象编程语言,主要用于iOS和Mac OS开发. C语言的基础上,增加了一层最小的面向对象语法 完全兼容C语言 可以在OC代码中混入C语言代码 ...
- Cs231n课堂内容记录-Lecture 3 最优化
Lecture 4 最优化 课程内容记录: (上)https://zhuanlan.zhihu.com/p/21360434?refer=intelligentunit (下)https://zhua ...
- echo 1+2+"3+4+5“输出的结果是6
如上,为什么echo 1+2+"3+4+5"输出的结果是6呢?刚开始我也不是很明白,以为有问题,但在电脑上运行程序的时候,结果出现6 了.这让我更加疑惑不解.现将问题解释一番. 在 ...
- WIndows 使用VS编译 Lua5
从Lua5.1开始官方给出的文件只有源代码和makefile文件了,官网给出的bulid方式也是在linux平台,如果只是想找个库使用下可以到这里来下载:http://joedf.ahkscript. ...
- vue-router 管理视图详解
什么是路由 在web开发中,路由是指根据url分配到对应的处理程序,当访问不同的url就会切换到对应的处理程序 在vue中一个url对应的就是一个组件,当访问不同的url,对应的组件就会呈现到页面中 ...
- 2.01-request_header
import urllib.request def load_baidu(): url= "https://www.baidu.com" header = { #浏览器的版本 &q ...