覆盖的面积(线段树+扫描线+离散化)

覆盖的面积

Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 21   Accepted Submission(s) : 13
Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.


 

Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 注意:本题的输入数据较多,推荐使用scanf读入数据.
 

Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
 

Sample Input
  
  
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
 

Sample Output
  
  
7.63 0.00
 

Author
Ignatius.L & weigang Lee
 

Statistic |  Submit |  Back

和今天做的这个题  Atlantis  博客地址:http://blog.csdn.net/sinat_37668729/article/details/78234266一个类型的题目,只不过它们的问题不同,一个是求面积(总面积不包括重复),一个是求面积(重复两次以上的),我的代码是在上个代码的基础上改的。

代码:

#include <iostream>  
#include <cstdio> 
#include <cstring> 
#include <algorithm>  
using namespace std; 
#define L(rt) (rt<<1)  
#define R(rt) (rt<<1|1)
#define INF 0x3f3f3f3f
#define maxn 2010 
struct Node{  
    double x;
	double y1;
	double y2;  
    int flag;  
}node[maxn]; //用来记录重叠情况,可以根据这个来计算,node节点中的len

bool cmp(Node a,Node b){  
    return a.x<b.x;  
}

double y[maxn];//记录y坐标的数组
  
struct node{  
    int l;//线段树左整点点
	int r;//右整点
	double ml;
	double mr;//ml和mr分别是对应的左右真实的浮点数端点 
	int s;//记录重叠情况
	double len;
	double cnt;  //cnt是值被覆盖一次以上的长度,len值被覆盖两次以上的长度
}a[maxn*3];  //注意,如果<<2会超时。。。。

void build(int i,int left,int right){  //建树
    a[i].l=left;
    a[i].r=right;
    a[i].ml=y[left];
    a[i].mr=y[right]; 
    a[i].s=0;
    a[i].len=a[i].cnt=0;
    if(a[i].l+1==a[i].r){  
        return;
    }
    int mid=(left+right)>>1;  
    build(L(i),left,mid);  
    build(R(i),mid,right);
}

void callen(int i){  //计算长度
  
    if(a[i].s>=2){ //该区间被覆盖两次及以上
        a[i].len=a[i].cnt=a[i].mr-a[i].ml; 
        return;
	}
	
	else if(a[i].s==1)//该区间被覆盖一次
	{  
		a[i].cnt=a[i].mr-a[i].ml;
		if(a[i].l+1==a[i].r)
        a[i].len=0;
        else
        a[i].len=a[L(i)].cnt+a[R(i)].cnt;	  
    }
	else{  //该区间
    	if(a[i].l+1==a[i].r) //子节点
    	a[i].len=a[i].cnt=0;
		else{ //非子节点
        a[i].len=a[L(i)].len+a[R(i)].len;
        a[i].cnt=a[L(i)].cnt+a[R(i)].cnt;
	}
}
    return;  
}

void updata(int i,Node b)//加入线段后,更新线段树
{  
    if(a[i].ml==b.y1&&a[i].mr==b.y2){  //恰好是当前的区间
        a[i].s+=b.flag;
        callen(i);
        return ; 
    }
    if(b.y2<=a[L(i)].mr) updata(L(i),b);  //需要更新的区间在当前节点的左孩子节点中 
    else if(b.y1>=a[R(i)].ml) updata(R(i),b);  //需要更新的区间在当前节点的右孩子节点中 
    else{//横跨左右两个孩子节点
        Node temp=b;  
        temp.y2=a[L(i)].mr;  
        updata(L(i),temp);  
        temp=b;
        temp.y1=a[R(i)].ml;  
        updata(R(i),temp);  
    }  
    callen(i);  
    return ;  
}
int main(){  
    int n,ans,cas=1,te;
	int t;  
    double x1,x2,y1,y2;
    scanf("%d",&t);
    while(t--){
			scanf("%d",&n); 
            ans=1;  
            for(int i=0;i<n;i++){  
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);  
            node[ans].x=x1;  
            node[ans].y1=y1;  
            node[ans].y2=y2;  
            node[ans].flag=1;
            y[ans++]=y1;
            node[ans].x=x2;  
            node[ans].y1=y1;  
            node[ans].y2=y2;  
            node[ans].flag=-1;
            y[ans++]=y2;
        }
        sort(node+1,node+ans,cmp);  
        sort(y+1,y+ans); 
        build(1,1,ans-1);  
        updata(1,node[1]); 
        double sum=0;  
        for(int i=2;i<ans;i++){  
            sum+=a[1].len*(node[i].x-node[i-1].x);  
            updata(1,node[i]);
        } 
        printf("%.2lf\n",sum);  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值