题目: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——扫描线+线段树的更多相关文章

  1. poj1151 Atlantis (线段树+扫描线+离散化)

    有点难,扫描线易懂,离散化然后线段树处理有点不太好理解. 因为这里是一个区间,所有在线段树中更新时,必须是一个长度大于1的区间才是有效的,比如[l,l]这是一根线段,而不是区间了. AC代码 #inc ...

  2. POJ 1151 Atlantis (扫描线+线段树)

    题目链接:http://poj.org/problem?id=1151 题意是平面上给你n个矩形,让你求矩形的面积并. 首先学一下什么是扫描线:http://www.cnblogs.com/scau2 ...

  3. [HDU1542]Atlantis(扫描线+线段树)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  4. 【POJ1151】Atlantis(线段树,扫描线)

    [POJ1151]Atlantis(线段树,扫描线) 题面 Vjudge 题解 学一学扫描线 其实很简单啦 这道题目要求的就是若干矩形的面积和 把扫描线平行于某个轴扫过去(我选的平行\(y\)轴扫) ...

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

    题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> ...

  6. HDU 3642 - Get The Treasury - [加强版扫描线+线段树]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Others) Memory L ...

  7. 【BZOJ3958】[WF2011]Mummy Madness 二分+扫描线+线段树

    [BZOJ3958][WF2011]Mummy Madness Description 在2011年ACM-ICPC World Finals上的一次游览中,你碰到了一个埃及古墓. 不幸的是,你打开了 ...

  8. 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 ...

  9. 【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树

    题目描述 给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串 输入 第一行n,表示A数组有多少元素接下来一行为n个整数A[i]接下来一个整数Q,表示询问数 ...

随机推荐

  1. 基于ACCESS和ASP的SQL多个表查询与计算统计代码(一)

    近期在写几个关于"Project - Subitem - Task"的管理系统,说是系统还是有点夸大了,基本就是一个多表查询调用和insert.update的数据库操作.仅仅是出现 ...

  2. wdatepicker ie8等问题

    官方文档:http://www.my97.net/demo/resource/2.4.asp 以下内容为使用中遇到的问题,具体该插件具有的方法请自行查阅官方文档. 1.当触发wdatepicker事件 ...

  3. asp .net 为图片添加文字水印(内包含有加图片水印的方法) .

    在项目中先创建一个Imag_writer 类库 在该类库下分别创建两个枚举类型WaterMarkType (水印的类型).WaterMarkPosition (水印的位置).代码如下: using S ...

  4. logstash+es+kibana+redis搭建

    环境信息: CentOS 6.5 redis 3.0.4 logstash elasticsearch kibana 服务端ip:192.168.0.65 客户端ip:192.168.0.66 关系结 ...

  5. [Codevs 1230]元素查找(手写哈希表)

    题目连接:http://codevs.cn/problem/1230/ 说白了就是要我们自己手写一个哈希表的数据结构来实现加入和查找功能.map也能直接过(我第一次写就是用map骗AC的) 提一下个人 ...

  6. Android gdb so

    gdb debug an android application 1.gdb 要有gdbserver 一般模拟器默认装有gdbserver,如2.3.3的模拟器,看一下有没有: D:\Develope ...

  7. 福昕熊雨前:PDFium开源项目的背后

    今天编译android的时候,无意中看到命令行提示出输出编译external/pdfium这个目录,于是乎上百度搜索了一下,找到了如下关于PDF文件解析的开源代码的文章: http://www.csd ...

  8. HashSet、LinkHashSet、TreeSet总结

    HashSet:散列集,集合中的元素不允许重复,但是不要求顺序,输出的顺序和进入HashSet的顺序是没有关系的 LinkedHashSet :链表散列集,集合中的元素不允许重复,同时要求和进入Set ...

  9. EasyRTMP视频直播推送H264 sps解析错误导致播放画面拉伸问题解决

    EasyRTMP是将H264流以及AAC流以RTMP协议推送到RTMP服务器上进行直播.EasyRTMP推送库中会从H264流中提取中SPS.PPS进行解析,开发的时候遇到过有些SPS解析有误,获取到 ...

  10. 开源服务器监控工具 — JavaMelody 类 jvm 内在性能(转)

    开源服务器监控工具 — JavaMelody     JavaMelody它能够监测Java或Java EE应用程序服务器,并以图表的方式显示:Java内存和Java CPU使用情况,用户Sessio ...