POJ 1151 扫描线+线段树+离散化

//考察:线段树+离散化+扫描线
//PE 一次,最后还要再输出一个空行 
#include<iostream>
#include<algorithm>
using namespace std;


struct seg{
    double x,y1,y2;
    int flag;//加入矩形最开始那条边为+1,加入矩形对边的时候为-1 
    seg(double a,double b,double c,int d):x(a),y1(b),y2(c),flag(d){}
    seg(){};
};
seg line[205];
int cmp(seg a,seg b){
    return a.x<b.x;
}
struct Node{
    int l,r;
    double yl,yr;
    //cover这个变量很有用,每当加入矩形的一条对边时候,实际上是将该线段抹掉了
    //所以只有当cover>0的时候,才能说明该段线段被覆盖了 
    int cover;
    Node(int a,int b,double l,double r,int cv,double len):l(a),r(b),yl(l),yr(r),cover(cv){}
    Node(){}
};
Node tree[205*4];
double y[205];

void build(int root,int l,int r){
    //y的用途在这儿 
    tree[root]=Node(l,r,y[l],y[r],0);
    int mid=(l+r)>>1;
    if(l+1==r)
        return;
    build(root*2,l,mid);
    build(root*2+1,mid,r);
}
//插入线段,注意flag的修改 
void insert(int root,seg b){
    if(b.y2<=tree[root].yl||b.y1>=tree[root].yr)
        return;
    if(b.y1<=tree[root].yl&&b.y2>=tree[root].yr){
        tree[root].cover+=b.flag;
        return;
    }
    insert(root*2,b);
    insert(root*2+1,b);
}
double ss;
void Count(int root){
    if(tree[root].cover>0){
        ss+=(tree[root].yr-tree[root].yl);
        return;
    }
    if(tree[root].r-tree[root].l==1)
        return;
    Count(root*2);
    Count(root*2+1);
}

int n;
double x1,x2,y1,y2; 
int main(){
    int cases=0;
    while(scanf("%d",&n)!=EOF&&n){
        cases++;
        int m=0;
        while(n--){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[++m]=seg(x1,y1,y2,1);y[m]=y1;
            line[++m]=seg(x2,y1,y2,-1);y[m]=y2;
        }
        //离散化 
        sort(line+1,line+1+m,cmp);sort(y+1,y+1+m);
        build(1,1,m);
        double sum=0;
        for(int i=1;i<m;i++){
            insert(1,line[i]);
            ss=0;
            Count(1);
            sum+=ss*(line[i+1].x-line[i].x);
        }
        printf("Test case #%d\n",cases);
        printf("Total explored area: %.2lf\n",sum);
        printf("\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值