poj1151

参考http://wenku.baidu.com/view/99fef963783e0912a2162adb.html

基本思路,每个扫描线里存一条纵向边,记录矩形的x坐标和y轴覆盖的范围,矩形左边界的flag为1右边界的flag为-1

那么对所有的矩形都这样建边,然后安x左边从小到大排序所有的扫描线,然后计算面积的时候从左到右查看每条扫描线覆盖的

面积,这个过程通过一个线段树优化,每次加入一条扫描线到树中,相应扫描线范围的cover值+flag,然后统计此时有cover值大于0的线段的总长

那么从这些线段到下一个扫描线的之间一定有面积。因为每加入一个矩形的左边界那么所对应的线段范围的cover加一,每加入一个右边界,对应的cover减一,

所以cover>0的线段范围到下一个扫描线之间的范围一定有面积。

如题目那样,加入第一条线10-20 flag=1

10-20=1

加入第二条线15-25.5 flag=1

10-15=1,15-20=2,20-25.5=1

加入第三条10-20 flag=-1

10-15=0,15-20=1,20-25.5=1

加入15-25.5 flag=-1

10-15=0 15-20=0 20-25.5=0

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define L(x) (x<<1)
#define R(x) (x<<1 | 1)
#define MAX 200
using namespace std;
double cy[2*MAX];
class Seg
{
    public :
        double x,y1,y2;
        int f;
        Seg(){};
        Seg(double a,double b,double c,int d):x(a),y1(b),y2(c),f(d)
        {
        }
        bool operator <(const Seg &b)const
        {
            return x<b.x;
        }
}seg[2*MAX];
struct node
{
    int l;
    int r;
    int cover;
    double length;
}a[MAX*3];
void build(int t,int l ,int r)
{
    a[t].l=l;
    a[t].r=r;
    a[t].cover=0;
    a[t].length=0;
    if(r-l==1)return ;
    int mid =(l+r)>>1;
    build(L(t),l,mid);
    build(R(t),mid,r);
}
void len(int t)
{
    if(a[t].cover>0)
      a[t].length=cy[a[t].r]-cy[a[t].l];
    else
    {
        if(a[t].r-a[t].l==1)a[t].length=0;
        else
          a[t].length=a[L(t)].length+a[R(t)].length;
    }
}
void update(int t,Seg &s)
{
    int tl=a[t].l;
    int tr=a[t].r;
    if(cy[tl]==s.y1&&cy[tr]==s.y2)
    {
        a[t].cover+=s.f;
        len(t);
        return ;
    }
    int mid=(tl+tr)>>1;
    if(s.y2<=cy[mid])
      update(L(t),s);
    else
      if(s.y1>=cy[mid])
        update(R(t),s);
      else
      {
          Seg temp=s;
          temp.y2=cy[mid];
          update(L(t),temp);
          temp=s;
          temp.y1=cy[mid];
          update(R(t),temp);
      }
    len(t);
}
int main()
{
    int n,m;
    int i,j;
    double x1,x2,y1,y2;
    int ca=1;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        m=0;        
        for(i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            seg[++m]=Seg(x1,y1,y2,1);
            cy[m]=y1;
            seg[++m]=Seg(x2,y1,y2,-1);
            cy[m]=y2;
        }
        sort(seg+1,seg+1+m);
        sort(cy+1,cy+1+m);
        build(1,1,m);
        double ary=0;
        for(i=1;i<=m-1;i++)
        {
            update(1,seg[i]);
            ary+=a[1].length*(seg[i+1].x-seg[i].x);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n",ca,ary);
        ca++;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值