HDU 1255 覆盖的面积 (线段树扫描线+面积交)
自己YY了一个的写法,不过时间复杂度太高了,网上的想法太6了
题意:给你一些矩阵,求出矩阵的面积并
首先按照x轴离散化线段到线段树上(因为是找连续区间,所以段建树更加好做)。
然后我们可以想一下怎样才能使面积相交呢?我们可以注意到如果矩阵入线出现超过一次就一定有面积相交,所以我们记录入线与出线,再排序y轴,从小到大(注意y轴等大时先进后出)扫描线段。
记录:总长度,当前一整段一起覆盖一次的长度,当前一整段一起覆盖超过一次的长度,当前一整段一起覆盖覆盖的次数(注意这一整段的情况不会更新到孩子节点)为什么是当前一整段且不更新呢?因为我们要计算的是插入这一段(入线或出线)后,所有的线覆盖超过一次的长度。如果仅仅计算入线中超过一次线覆盖的长度,就会少计算一些面积,原因是我们每次会把y轴更新,这样就还有一些不在现在入线这一段中却覆盖超过一次的线段没有统计。
入线:矩阵下方的x轴的线(按照y轴扫描),表示矩阵进入扫描线,开始计算
出现:矩阵上方的x轴的线(按照y轴扫描),表示矩阵已经出去,不能计算了
/*给一些矩阵求矩阵面积交:离散化x轴,排序y轴扫描,注意记录一个cover,关键在此cover表示仅仅次一连续段的覆盖情况们不要更新到孩子节点
而此时只需要记录区间覆盖两次及以上的长度是多少就好*/
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
const int Max=<<;//每个矩形扫描时看做两条线
struct node
{
double len[];//线段本身长度,覆盖次数为1次,覆盖次数大于1次的线段的长度
int cover;//表示这一段被覆盖的次数
}segtr[Max];
struct nide
{
int typ;
double xx1,xx2,yy1;
}lin[Max];
map<double,int> mp;//快速找到某个x所对应的树上的点
double llin[Max];//离散化到树上对应节点
bool cmp(struct nide p1,struct nide p2)
{
if(p1.yy1==p2.yy1)
return p1.typ>p2.typ;//关键 同一个位置先进后出
return p1.yy1<p2.yy1;
}
void Create(int sta,int enn,int now)
{
segtr[now].cover=;
segtr[now].len[]=llin[enn]-llin[sta];
segtr[now].len[]=segtr[now].len[]=0.0;
if(sta+==enn)//为了处理连续段可能没有包含完整的情况采用段建树
return;
int mid=dir(sta+enn,);
int next=mul(now,);
Create(sta,mid,next);
Create(mid,enn,next|);
return;
}
void Upnow(int now,int sta,int enn)//主要的函数
{
int next=mul(now,);//注意现在的flag仅仅代表这一条线连续在一起的的情况,但是这一条线如果分成几段的话就不一定是这样的,即**这个flag并不代表这一线所以的情况**
if(segtr[now].cover>=)
{
segtr[now].len[]=0.0;
segtr[now].len[]=segtr[now].len[];
}
else if(segtr[now].cover==)//此线段被覆盖一次,则孩子节点的线段覆盖情况就应该都加一次,注意此点与孩子节点的覆盖次数不相干
{
if(sta+!=enn)
segtr[now].len[]=segtr[next].len[]+segtr[next|].len[]+segtr[next].len[]+segtr[next|].len[];
else
segtr[now].len[]=0.0;
segtr[now].len[]=segtr[now].len[]-segtr[now].len[];//len 1+2 == 0
}
else
{
if(sta+==enn)
{
segtr[now].len[]=0.0;
segtr[now].len[]=0.0;
}
else
{
segtr[now].len[]=segtr[next].len[]+segtr[next|].len[];
segtr[now].len[]=segtr[next].len[]+segtr[next|].len[];
}
}
return;
}
void Update(int sta,int enn,int now,int x,int y,int z)
{
if(sta>=x&&enn<=y)
{
segtr[now].cover+=z;
Upnow(now,sta,enn);//更新len
return;
}
int mid=dir(sta+enn,);
int next=mul(now,);
if(mid>x)
Update(sta,mid,next,x,y,z);
if(mid<y)
Update(mid,enn,next|,x,y,z);
Upnow(now,sta,enn);
return;
}
double Solve(int m,int cnt)
{
double ans=0.0;
sort(lin,lin+m,cmp);
Create(,cnt,);
for(int i=;i<m;i++)//按照y轴从前到后扫描
{
if(i)
ans+=segtr[].len[]*(lin[i].yy1-lin[i-].yy1);//添加后计算,注意计算的时候要延迟一次
Update(,cnt,,mp[lin[i].xx1],mp[lin[i].xx2],lin[i].typ);
}
return ans;
}
int main()
{
int t,n,m,cnt;
scanf("%d",&t);
while(t--)
{
mp.clear();
scanf("%d",&n);
m=;
for(int i=;i<n;i++)
{
scanf("%lf %lf %lf %lf",&lin[m].xx1,&lin[m].yy1,&lin[m+].xx2,&lin[m+].yy1);
lin[m].xx2=lin[m+].xx2,lin[m+].xx1=lin[m].xx1;
lin[m].typ=,lin[m+].typ=-;//进线与出线
mp[lin[m].xx1]=,mp[lin[m].xx2]=;
m+=;
}
cnt=;//从1开始,关键关键
for(map<double,int>::iterator it=mp.begin();it!=mp.end();++it)
{
it->second=cnt;
llin[cnt++]=it->first;
}
cnt--;//注意不能多
printf("%.2f\n",Solve(m,cnt));
}
return ;
}
HDU 1255 覆盖的面积 (线段树扫描线+面积交)的更多相关文章
- HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)
版权声明:欢迎关注我的博客.本文为博主[炒饭君]原创文章,未经博主同意不得转载 https://blog.csdn.net/a1061747415/article/details/25471349 P ...
- hdu1255 覆盖的面积 线段树-扫描线
矩形面积并 线段树-扫描线裸题 #include<stdio.h> #include<string.h> #include<algorithm> #include& ...
- HDU 4419 Colourful Rectangle --离散化+线段树扫描线
题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...
- poj1511,线段树扫描线面积
经典题,线段树扫描线其实类似区间更新,一般的做法是想象一根扫描线从上扫到下或者从左扫到右,本题的做法是从上扫到下 只要扫到了一根水平线,就将其更新到线段树对应区间中,区间和它的子区间是独立更新的 #i ...
- HDU 1255 覆盖的面积 (线段树+扫描线+离散化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 题意很清楚,就是让你求矩阵之间叠加层数大于1的矩形块的面积和. 因为n只有1000,所以我离散化 ...
- hdu 1255 覆盖的面积 (线段树处理面积覆盖问题(模板))
http://acm.hdu.edu.cn/showproblem.php?pid=1255 覆盖的面积 Time Limit: 10000/5000 MS (Java/Others) Memo ...
- HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化
题目链接:https://vjudge.net/problem/HDU-1255 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<= ...
- HDU 1255 覆盖的面积 线段树+扫描线
同 POJ1151 这次是两次 #include <iostream> #include <algorithm> #include <cstdio> #includ ...
- hdu 1542&&poj 1151 Atlantis[线段树+扫描线求矩形面积的并]
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
随机推荐
- Hibernate二次学习一----------搭建Hibernate
目录 1. 项目结构 1.2 hibernate.cfg.xml 1.3 entity 1.4 entity.hbm.xml 2. 测试 3. 总结 © 版权声明:本文为博主原创文章,转载请注明出处 ...
- 简易web服务器(java版)
//直接使用 ServerSocket 监听服务器端口,就能实现web服务器package ThreadPoolTest; import java.io.InputStream; import jav ...
- GNU LD 脚本学习笔记
LD脚本(linker script)是什么 GNU ld是链接器,ld实际并不是GCC的一部分,ld属于binutils软件包.但是嵌入式开发时,下载的linaro GCC工具集中是包含 arm-l ...
- mapreduce学习资料
http://blog.csdn.net/tianjun2012/article/category/6794531 http://blog.csdn.net/tianjun2012/article/d ...
- 交换两个变量的值不使用第三个变量(Java)
关于这个问题网上有好多答案,最近有人说这是个奇葩问题 个人测试了一把,如果是普通的数字的话,基本上没有问题 public static void main(String[] args) { int a ...
- window安装redis
1.redis简介redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(so ...
- 【JMeter4.0学习(十)】之JMeter函数简单运用以及结合正则表达式提取器
下面来简单的举个栗子: 首先,把函数和正则表达式提取器放在一块来介绍,如下所示: 1.结构完整展示,下面再一步一步创建添加: 2.添加线程组: 3.首先添加HTTP请求1 4.添加结果树后,运行后查看 ...
- 在Ubuntu下利用Eclipse开发FFmpeg配置小结
首先需要编译FFmpeg得到头文件和lib文件,参见:在Ubuntu下编译FFmpeg 选择File-New-C Project 选择Executable下的Empty Project,右侧选择Lin ...
- java 对象占用内存查看 以及JVM级别 方法修改等
public interface Instrumentation 此类提供检测 Java 编程语言代码所需的服务.检测是向方法中添加字节码,以搜集各种工具所使用的数据.由于更改完全是进行添加,所以这些 ...
- (一)unity4.6Ugui中文教程文档-------概要
大家好,我是孙广东. 转载请注明出处:http://write.blog.csdn.net/postedit/38922399 更全的内容请看我的游戏蛮牛地址:http://www.unityma ...