题目: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. NGUI版虚拟摇杆

    以下是我用nui实现的一个虚拟摇杆. 1,示图 2.代码例如以下,都有比較具体的凝视.就不说明了. using UnityEngine; using System.Collections; using ...

  2. 串匹配算法之BM算法

    参考资料: http://blog.csdn.net/eric491179912/article/details/6210009   http://blog.163.com/pengfeicui@ye ...

  3. asyncio协程与并发

    并发编程 Python的并发实现有三种方法. 多线程 多进程 协程(生成器) 基本概念 串行:同时只能执行单个任务 并行:同时执行多个任务 在Python中,虽然严格说来多线程与协程都是串行的,但其效 ...

  4. python 修饰符(转载)

    首先一个修饰符的实例: #!/usr/bin/env python def run(fn): def do_hello(): print "begin..." fn() print ...

  5. Linux 系统编程中环境变量的使用

    前言 在 UNIX Like 系统中,存有各类系统/应用程序的环境变量,可通过修改之改变系统/应用程序的执行效果:除此之外,用户还可以定义自己的环境变量,供自己写的程序使用.本文将说明如何在程序中设置 ...

  6. iOS开发之──传感器使用

    本文转载至 http://mobile.51cto.com/iphone-423219.htm 在实际的应用开发中,会用到传感器,下面首先介绍一下iphone4的传感器,然后对一些传感器的开发的API ...

  7. uGUI动态加载控件位置错误(转自:https://www.cnblogs.com/mezero/p/4542939.html)

    最近在使用uGUI时遇到了一个问题,在此记录一下.在Canvas的Render Mode设置为Screen Space-Overlay模式时,动态加载控件是不会发生问题的.但是在Screen Spac ...

  8. 【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并

    [BZOJ1483][HNOI2009]梦幻布丁 Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2 ...

  9. python中的括号以及元组和列表的区别

    1 python中的括号 1.1 花括号 花括号表示的是字典,即键值对. 1.2 方括号 方括号表示的是列表,类似于数组,但是可以允许存放混杂类型的数据. 1.3 圆括号 圆括号表示的是元组,类似于列 ...

  10. mybatis入门小结(六)

    入门小结---查询 1.1.1.1.1 #{}和${} #{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以 ...