POJ 1151 Atlantis 线段树+离散化

题意比较简单,给出平面上一系列矩形,求出总的覆盖面积。本题数据量不是很大,矩形数量最多100个,其实可以不用线段树的,不过的确是很经典的线段树类型的题。

1.用line结构体数组记录各纵边,标记左边和右边。

2.矩形的长度范围达到200000,有必要先进行离散化处理,用Index数组来保存横坐标。

3.对Index和纵向的线段进行排序,排序的时候使用STL里的sort函数会比较高效,(我用sort排序AC的时间是16ms,改成qsort以后就变成了32ms,汗一个)。对结构体排序,我所知道的有两种方法,一种是重载运算符,使结构体之间能直接比较,另一种是类似qsort函数,编写比较函数加入到sort里使用,效果一样。

4.接下来就是简单的运用线段树了,线段树结构体里面加一个sum成员,用来记录当前区间上的覆盖长度,每次执行操作后进行更新,然后记录面积的增加量。

最后说点要注意的东西,这些我花了一下午才调出来,感觉收获很大,呵呵。

1.保存长度和坐标的时候要用浮点型,记录坐标对应Index下标和线段树上点要用整型,千万不能弄混

2. 求取坐标对应的Index下标时要自己手写函数,不能使用STL的lower_bound函数

3.计算两个坐标是否相等时不能直接用==,应该是<=极小数

注意这几个地方就没问题了, 这个题关于数据精度处理给我上了印象深刻的一课,谨记。

//1151 Accepted 252K 16MS C++ 1855B

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define mi 0.00001
struct Line{
 double x,up,down;
 int state;
 void set(double xx,double y1,double y2,int s){x=xx,down=y1,up=y2,state=s;}
 int operator <(const Line &a){return x<a.x;}
};Line line[200];
struct Node {
 int cover,s,t;
 double sum;
 Node *l,*r;
}*root,mempool[400];
double Index[200];
int memh,n,m;
void build(Node *&root,int s,int t)
{
 root=&mempool[memh++];
 root->s=s;
 root->t=t;
 root->cover=root->sum=0;
 root->l=root->r=NULL;
 if(t-s>1) {
  int mid=(s+t)>>1;
  build(root->l,s,mid);
  build(root->r,mid,t);
 }
}
void operate(Node *&root,int s,int t,int order)
{
 if(root->s>=s&&t>=root->t)
  root->cover+=order;
 else {
  int mid=(root->s+root->t)>>1;
  if(s<mid) operate(root->l,s,t,order);
  if(t>mid) operate(root->r,s,t,order);
 }
 if(root->cover)
  root->sum=Index[root->t]-Index[root->s];
 else if(root->t-root->s>1) 
  root->sum=root->l->sum+root->r->sum;
 else root->sum=0;
}
int getIndex(double i)
{
 int j=0;
 for(j=0;j<=m;j++)
  if(fabs(i-Index[j])<=mi)
  return j;
}
int main()

 int i,cs=0;
 double ux,uy,dx,dy,ans;
 while(scanf("%d",&n)!=EOF&&n) {
  for(i=0;i<n;i++) {
  scanf("%lf%lf%lf%lf",&dx,&dy,&ux,&uy);
  line[2*i].set(dx,dy,uy,1);
  line[2*i+1].set(ux,dy,uy,-1);
  Index[2*i]=uy,Index[2*i+1]=dy;
  }
  sort(Index,Index+2*n);
  sort(line,line+2*n);
  for(i=1,m=memh=0;i<2*n;i++)
  if(Index[i]!=Index[i-1])
  Index[m++]=Index[i-1];
  Index[m]=Index[2*n-1];
  root=NULL;
  build(root,0,m);
  ans=0;
  for(i=0;i<2*n-1;i++) {
  operate(root,getIndex(line[i].down),getIndex(line[i].up),line[i].state);
  ans+=(line[i+1].x-line[i].x)*root->sum;
  }
  printf("Test case #%d/nTotal explored area: %.2lf/n/n",++cs,ans);
 }
 return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值