POJ 1151 - Atlantis 线段树+扫描线..


分类: 线段树   297人阅读  评论(1)  收藏  举报

   离散化: 将所有的x轴坐标存在一个数组里..排序.当进入一条线段时..通过二分的方式确定其左右点对应的离散值...

   扫描线..可以看成一根平行于x轴的直线..至y=0开始往上扫..直到扫出最后一条平行于x轴的边..但是真正在做的时候..不需要完全模拟这个过程..扫描线的做法是从最下面的边开始扫到最上面的边.

   线段树: 本题用于动态维护扫描线在往上走时..x哪些区域是有合法面积的..

   几个图说明扫描线扫描..线段树维护的过程..:


初始状态


扫到最下边的线,点更新1~3为1


扫到第二根线,此时将计数器不为0的长度*上线两根线的长度,得到绿色的面积,加到答案中去.随后更新计数


同上,将黄色的面积加到答案中去


同上,将灰色的面积加到答案中去


同上,将紫色的面积加到答案中去


同上,将蓝色的面积加到答案中去


Program:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<stdio.h>  
  3. #include<string.h>  
  4. #include<set>  
  5. #include <ctime>  
  6. #include<queue>  
  7. #include<algorithm>  
  8. #include<cmath>  
  9. #define oo 1000000007  
  10. #define ll long long  
  11. #define pi acos(-1.0)  
  12. #define MAXN 405  
  13. using namespace std;  
  14. struct node  
  15. {  
  16.       double l,r,y;  
  17.       int tp;  
  18.       bool operator <(node a) const  
  19.       {  
  20.             return y<a.y;  
  21.       }  
  22. }line[MAXN<<2];  
  23. int n,Times[MAXN<<2];  
  24. double X[MAXN<<2],sum[MAXN];  
  25. int b_search(double x)  
  26. {  
  27.       int l,r,mid;  
  28.       l=0,r=n+1;  
  29.       while (r-l>1)  
  30.       {  
  31.             mid=(l+r)>>1;  
  32.             if (X[mid]<=x) l=mid;  
  33.                else r=mid;  
  34.       }  
  35.       return l;  
  36. }  
  37. void update(int x,int c,int l,int r,int now)  
  38. {  
  39.       if (l==r)  
  40.       {  
  41.             Times[x]+=c;  
  42.             if (Times[x]) sum[now]=X[x+1]-X[x];  
  43.             if (!Times[x]) sum[now]=0;  
  44.             return;  
  45.       }  
  46.       int mid=(l+r)/2;  
  47.       if (x<=mid) update(x,c,l,mid,now<<1);  
  48.       if (mid<x)  update(x,c,mid+1,r,(now<<1)|1);  
  49.       sum[now]=sum[now<<1]+sum[(now<<1)|1];  
  50.       return;  
  51. }  
  52. int main()  
  53. {   
  54.       int i,j,num,T=0;  
  55.       double ans=0;   
  56.       while (~scanf("%d",&n) && n)  
  57.       {  
  58.             num=0;  
  59.             for (i=1;i<=n;i++)  
  60.             {  
  61.                    double x1,y1,x2,y2;  
  62.                    scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);  
  63.                    line[i*2-1].y=y1,line[i*2-1].l=x1,line[i*2-1].r=x2,line[i*2-1].tp=1;  
  64.                    line[i*2].y=y2,line[i*2].l=x1,line[i*2].r=x2,line[i*2].tp=-1;  
  65.                    X[++num]=x1,X[++num]=x2;  
  66.             }  
  67.             n=n*2;  
  68.             sort(X+1,X+1+num);  
  69.             sort(line+1,line+1+n);  
  70.             memset(sum,0,sizeof(sum));  
  71.             memset(Times,0,sizeof(Times));  
  72.             ans=0;  
  73.             for (i=1;i<=n;i++)  
  74.             {  
  75.                    ans+=sum[1]*(line[i].y-line[i-1].y);   
  76.                    int l,r;  
  77.                    l=b_search(line[i].l);  
  78.                    r=b_search(line[i].r)-1;  
  79.                    for (j=l;j<=r;j++) update(j,line[i].tp,1,n-1,1);  
  80.             }  
  81.             printf("Test case #%d\nTotal explored area: %.2f\n\n",++T,ans);  
  82.       }  
  83.       return 0;  
  84. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值