题目: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. 金山面试CDN

    History 今天去金山网络面试的时候,被问到性能优化,我说了几个.最后说到了CDN,我说要尽量把静态的内容放置到CDN,可是为什么呢?面试官说既然你说到CDN.你就说说它的原理. 之前有看过,可是 ...

  2. [Python-tools]defaultdict的使用场景

    Python标准库中collections对集合类型的数据结构进行了非常多拓展操作.这些操作在我们使用集合的时候会带来非常多的便利.多看看非常有优点. defaultdict是当中一个方法,就是给字典 ...

  3. 微型企业如何使用odoo

    作者 jeffery Q913547235 保留所有权利     Odoo可以帮助微型企业提升运营效率,做到电子化,信息化. 管理仓库进销存,建立收货单.交货单,并基于收货.交货情况确认应收款和应付款 ...

  4. python datetime获取几分钟、小时、天之前的时间

    import datetime print ((datetime.datetime.now()-datetime.timedelta(days=1)).strftime("%Y-%m-%d ...

  5. 两种IO模式:Proactor与Reactor模式

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...

  6. Swift的两个小窍门

    一:查看Swift版本号(How do I see which version of Swift I’m using in Xcode?) 终端下输入:xcrun swift -version(in ...

  7. win7-64bit下基于VMware12.5安装rhel-server-6.3-i386

    /************************************************************************************* 宿主PC:win7-64b ...

  8. tomcat 7安装

    JAVA环境安装 1.下载包 http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-x64.bin 2.安装 jdk-6u45 ...

  9. VLC RTP Over TCP

    在RTSP协议请求数据时,让VLC以TCP的方式获取服务器发来的RTP数据 不为别的,下次回复直接用博客链接就能回复大家了! 操作:工具 -> 首选项 然后: 搞定! ------------- ...

  10. Spring 配置JNDI数据源

    1.Spring 提供的JNDI调用类. 2.使用weblogic进行部署项目,所以使用WebLogicNativeJdbcExtrator类进行配置. 3.配置完数据源后配置sessionFacto ...