poj1151 Atlantis——扫描线+线段树
题目:http://poj.org/problem?id=1151
经典的扫描线问题;
可以用线段树的每个点代表横向被矩形上下边分割开的每一格,这样将一个矩形的出现或消失化为线段树上的单点修改;
每个格子记录两个值:c(矩形存在情况),sum(对当前答案作出贡献的长度);
将y离散化作为建树的依据;
一开始没想到线段树上的点应该是横向的格子,写了个乱七八糟:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,xt;
double s[],ans,tr[],mx,eps=0.36;
struct P{
double x,y1,y2;
int tp;
P(int x=,int y1=,int y2=,int t=):x(x),y1(y1),y2(y2),tp(t) {}
}p[];
void pushup(int x)
{
tr[x]=tr[x<<]+tr[x<<|];
}
void add(int x,double l,double r,double L,double R,int w)
{
// cout<<x<<endl;
// printf("l=%lf r=%lf eps=%lf\n",l,r,eps);
if(r-l<eps)
{
s[x]+=w;
if(s[x])tr[x]=;
else tr[x]=;
// printf("s[%d]=%d\n",x,s[x]);
return;
}
double mid=(l+r)/;
if(mid>=L)add(x<<,l,mid,L,R,w);
if(mid<R)add(x<<|,mid+,r,L,R,w);
pushup(x);
}
bool cmp(P x,P y){return x.x<y.x;}
int main()
{
while(scanf("%d",&n)==)
{
t++;xt=;mx=;ans=;
memset(tr,,sizeof tr);
memset(s,,sizeof s);
if(!n)return ;
for(int i=;i<=n;i++)
{
xt++;scanf("%lf%lf",&p[xt].x,&p[xt].y1);
xt++;scanf("%lf%lf",&p[xt].x,&p[xt].y1);
p[xt-].y2=p[xt].y1;p[xt].y2=p[xt-].y1;
p[xt-].tp=;p[xt].tp=-;
mx=max(mx,max(p[xt].y1,p[xt].y2));
}
sort(p+,p+xt+,cmp);
double lst=-;
for(int i=;i<=xt;i++)
{
if(p[i].y1>p[i].y2)swap(p[i].y1,p[i].y2);
add(,,mx,p[i].y1,p[i].y2,p[i].tp);
if(lst!=-)ans+=(p[i].x-lst)*tr[];
lst=p[i].x;
}
printf("Test case #%d\nTotal explored area: %.2lf \n",t,ans);
}
return ;
}
囧
然后参考别人的博客,努力理解了半天,模仿着打了出来,终于A了...
学到了add()函数里面那种二分的方法。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,ct,t;
double ans,y[];
struct P{
int l,r,c;//c为上下矩形抵消数
double ly,ry,sum;//sum为此时计入计算的长度
}tr[];
struct E{
int tp;
double x,ly,ry;
}ed[];
bool cmp(E x,E y){return x.x<y.x;}
void build(int x,int l,int r)
{
tr[x].l=l;tr[x].r=r;
tr[x].ly=y[l];tr[x].ry=y[r];
tr[x].c=;tr[x].sum=;
if(l==r-)return;
int mid=(l+r)>>;
build(x<<,l,mid);
build(x<<|,mid,r);//不是mid+1,因为l,r表示此块上下两边
}
void pushup(int x)
{
if(tr[x].c>)//全选
tr[x].sum=tr[x].ry-tr[x].ly;
else if(tr[x].l==tr[x].r-)//仅有一格且被退出
tr[x].sum=;
else//可能有其他边覆盖
tr[x].sum=tr[x<<].sum+tr[x<<|].sum;
}
void add(int x,E e)
{
if(tr[x].ly==e.ly&&tr[x].ry==e.ry)
{
tr[x].c+=e.tp;
pushup(x);
return;
}
if(tr[x<<].ry>=e.ry)add(x<<,e);
else if(tr[x<<|].ly<=e.ly)add(x<<|,e);
else
{
E tmp=e;
tmp.ry=tr[x<<].ry;
add(x<<,tmp);
tmp=e;
tmp.ly=tr[x<<|].ly;
add(x<<|,tmp);
}
pushup(x);
}
int main()
{
while(scanf("%d",&n)==)
{
t++;
if(!n)return ;
ct=;ans=;
for(int i=;i<=n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y[++ct]=y1;ed[ct].tp=;
ed[ct].x=x1;ed[ct].ly=y1;ed[ct].ry=y2;
y[++ct]=y2;ed[ct].tp=-;
ed[ct].x=x2;ed[ct].ly=y1;ed[ct].ry=y2;
}
sort(ed+,ed+ct+,cmp);
sort(y+,y+ct+);
build(,,ct);
add(,ed[]);
for(int i=;i<=ct;i++)
{
ans+=tr[].sum*(ed[i].x-ed[i-].x);
add(,ed[i]);//上下勿反
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",t,ans);
}
return ;
}
poj1151 Atlantis——扫描线+线段树的更多相关文章
- poj1151 Atlantis (线段树+扫描线+离散化)
有点难,扫描线易懂,离散化然后线段树处理有点不太好理解. 因为这里是一个区间,所有在线段树中更新时,必须是一个长度大于1的区间才是有效的,比如[l,l]这是一根线段,而不是区间了. AC代码 #inc ...
- POJ 1151 Atlantis (扫描线+线段树)
题目链接:http://poj.org/problem?id=1151 题意是平面上给你n个矩形,让你求矩形的面积并. 首先学一下什么是扫描线:http://www.cnblogs.com/scau2 ...
- [HDU1542]Atlantis(扫描线+线段树)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- 【POJ1151】Atlantis(线段树,扫描线)
[POJ1151]Atlantis(线段树,扫描线) 题面 Vjudge 题解 学一学扫描线 其实很简单啦 这道题目要求的就是若干矩形的面积和 把扫描线平行于某个轴扫过去(我选的平行\(y\)轴扫) ...
- hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积
题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> ...
- HDU 3642 - Get The Treasury - [加强版扫描线+线段树]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Others) Memory L ...
- 【BZOJ3958】[WF2011]Mummy Madness 二分+扫描线+线段树
[BZOJ3958][WF2011]Mummy Madness Description 在2011年ACM-ICPC World Finals上的一次游览中,你碰到了一个埃及古墓. 不幸的是,你打开了 ...
- HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)
Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...
- 【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树
题目描述 给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串 输入 第一行n,表示A数组有多少元素接下来一行为n个整数A[i]接下来一个整数Q,表示询问数 ...
随机推荐
- sql的一些知识_计算字段
创建计算字段 拼接字段 mysql中 使用concat拼接字段 得到的info可以被客户端使用 算术计算 对检索的数据进行运算并as为新的列名 ) ORDER BY weight
- MySQL的timeout那点事
http://www.mysqlops.com/2011/11/24/mysql_timeout.html
- error MSB8011: 未能注冊输出。请尝试启用“逐用户重定向”
初试MFC就遇到困难了.vs2010创建一个MFC ActiveX控件项目. 什么都还没做呢,就出现故障了? 郁闷呀.! ! 1>C:\Program Files\MSBuild\Microso ...
- 【NoSql】Redis实践篇-简单demo实现(一)
Redis是一个key-value存储系统. Redis的出现,非常大程度补偿了memcached这类key/value存储的不足,在部分场合能够对关系数据库起到非常好的补充作用 Redis是一个ke ...
- Linux Setuid(SUID)和Setgid(SGID) sticky bit
http://www.php100.com/html/webkaifa/Linux/2010/0812/6392.html 1.setuid和setgid的解说 setuid和setgid位是让普通用 ...
- Kubernetes基本概念之Label
系列目录 在为对象定义好Label后,其他对象就可以通过Label来对对象进行引用.Label的最常见的用法便是通过spec.selector来引用对象. apiVersion: v1 kind: R ...
- KVM技术
今天是周六,看到一片KVM相关的文章,感觉写得很不错,翻译了,原文在这里:KVM Technology 在开放服务器虚拟化的应用方面,KVM虚拟化技术近年来广受关注.自从2006年10月份诞生以来,其 ...
- Fakeapp2.2安装,使用简记
1,硬件和操作系统,支持cuda的Nvidia显卡,8G及以上的内存,Windows10 x64(推荐,Windows7 x64亲测可行),可以使用gpu-z查看你的显卡详情 我的笔记本是双显卡(都是 ...
- 用Q-learning算法实现自动走迷宫机器人
项目描述: 在该项目中,你将使用强化学习算法,实现一个自动走迷宫机器人. 如上图所示,智能机器人显示在右上角.在我们的迷宫中,有陷阱(红色炸弹)及终点(蓝色的目标点)两种情景.机器人要尽量避开陷阱.尽 ...
- YARN和MapReduce的内存设置參考
怎样确定Yarn中容器Container,Mapreduce相关參数的内存设置,对于初始集群,由于不知道集群的类型(如cpu密集.内存密集)我们须要依据经验提供给我们一个參考配置值,来作为基础的配置. ...