求矩形并的面积(线段树)【模板】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=210;
struct node{
    int left,right,c; //c : 区间被覆盖的层数, m: 区间的测度 
    double m;
}tree[N*4];
struct Line{
    double x,y1,y2;  //纵方向直线, x:直线横坐标, y1 y2:直线上的下面与上面的两个纵坐标
    int s;   //s = 1 : 直线为矩形的左边, s = 0:直线为矩形的右边
}line[N];
bool cmp(Line a,Line b){
    return a.x<b.x;
}
double ty[N],y[N];   //y[] 整数与浮点数的对应数组; ty[]:用来求y[]的辅助数组
void build(int t,int left,int right){
    tree[t].left=left;
    tree[t].right=right;
    tree[t].c=0;
    tree[t].m=0;
    if(left+1<right){
        int mid=(left+right)>>1;
        build(t<<1,left,mid);
        build((t<<1)+1,mid,right);
    }
}
void update(int t){
    if(tree[t].c>0) tree[t].m=y[tree[t].right]-y[tree[t].left];
    //将线段树上区间的端点分别映射到 y[]数组所对应的浮点数上,由此计算出测度 
    else if(tree[t].left+1==tree[t].right) tree[t].m=0; 
    else tree[t].m=tree[t<<1].m+tree[(t<<1)+1].m;
}
void insert(int t,int left,int right){
    if(left<=tree[t].left && tree[t].right<=right){
        tree[t].c++;
        update(t);
        return ;
    }
    int mid=(tree[t].left+tree[t].right)>>1;
    if(left<mid) insert(t<<1,left,right);
    if(right>mid) insert((t<<1)+1,left,right);
    update(t);
}
void del(int t,int left,int right){
    if(left<=tree[t].left && tree[t].right<=right){
        tree[t].c--;
        update(t);
        return ;
    }
    int mid=(tree[t].left+tree[t].right)>>1;
    if(left<mid) del(t<<1,left,right);
    if(right>mid) del((t<<1)+1,left,right);
    update(t);
}

int getindex(int n,double x){//二分查找出浮点数 t 在数组y[]中的位置(此即所谓的映射关系)
    int left,right,mid;
    left=1;right=n;
    while(left<=right){
        mid=(left+right)>>1;
        if(y[mid]<x) left=mid+1;
        else right=mid-1;
    }
    return left;
}
int main(){
    int n,i;
    double x1,y1,x2,y2;
    int cas=1;
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        for(i=0;i<n;i++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[i*2].x=x1; line[i*2].y1=y1; line[i*2].y2=y2; line[i*2].s=1;
            line[i*2+1].x=x2; line[i*2+1].y1=y1; line[i*2+1].y2=y2; line[i*2+1].s=0;
            ty[i*2]=y1;ty[i*2+1]=y2;
        }
        n<<=1;
        sort(line,line+n,cmp);
        sort(ty,ty+n);  //默认升序排序
        int num=1;
        y[1]=ty[0];
        for(i=1;i<n;i++){ //离散化处理数组 ty[]使之不含重覆元素,得到新的数组存放到数组y[]中 
            if(ty[i]!=ty[i-1]) y[++num]=ty[i];
        }
        build(1,1,num);//树的叶子节点与数组 y[]中的元素个数相同,以便建立一一对应的关系
        int left,right;
        double ans=0;
        for(i=0;i<n-1;i++){
            left=getindex(num,line[i].y1);  //由对应关系计算出线段两端在树中的位置
            right=getindex(num,line[i].y2);
            if(line[i].s==1)   //插入矩形的左边
                insert(1,left,right);
            else         //删除矩形的右边 
                del(1,left,right);
            ans+=tree[1].m*(line[i+1].x-line[i].x);
        }
        printf("Test case #%d\n",cas++);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}

代码转自:http://www.cnblogs.com/CXCXCXC/p/5003389.html(poj1151)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值