• Poj 1255 覆盖的面积 2014-07-28 12:29 116人阅读 评论(0) 收藏


    覆盖的面积

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 3553    Accepted Submission(s): 1743


    Problem Description
    给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.


     

    Input
    输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N&lt;=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

    #include<iostream>
    #include<cstdio>
    #include<algorithm> 
    #define Max 10005
    using namespace std;
    struct line{
    	double x, y1, y2;
    	int flag;
    }x_line[Max];
    
    struct node{
    	int l, r, flag;
    	double x, f;
    }tree[Max];
    
    double point[Max];
    int n, m, xm;
    
    int cmp(double a,double b)
    {
    	return a<b;
    }
    
    bool comp(line a,line b)
    {
        return a.x<b.x;
    }
    
    void Build(int l,int r,int k)
    {
    	int m;
    	tree[k].l = l;
    	tree[k].r = r;
    	tree[k].flag = 0;
    	tree[k].x = 0.0;
    	tree[k].f = 0.0;
    	if(l+1 == r)	return;
    	m = (l+r)>>1;
    	Build(l,m,k+k);
    	Build(m,r,k+k+1);
    }
    
    void Myscanf()
    {
    	m = 1;
    	double x1,x2,y1,y2;
    	scanf("%d",&n);
    	for(int i=0; i<n; i++)
    	{
    		scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    		point[m] = y1;
    		x_line[m].x = x1;
    		x_line[m].y1 = y1;
    		x_line[m].flag = 1;
    		x_line[m++].y2 = y2;
    		point[m] = y2;
    		x_line[m].x = x2;
    		x_line[m].y1 = y1;
    		x_line[m].flag = -1;
    		x_line[m++].y2 = y2;
    	}
    	
    }
    
    void Point_Do()
    {
    	int mi = 0;
    	sort(point+1,point+m,cmp);
    	sort(x_line+1,x_line+m,comp);
    	xm = m;
    	for(int i=1; i<m; i++)
    	{
    		if(point[i]!=point[mi])		point[++mi] = point[i]; 		//去重
    	}
    	m = mi;
    }
    
    int Bin(double xi)
    {
    	int l = 1, r = m;
    	int mi;
    	while(l<=r)
    	{
    		mi = (l+r)>>1;
    		if(xi == point[mi])	return mi;
    		if(xi > point[mi])	l = mi+1;
    		else r = mi-1;
    	}
    	return -1;
    }
    
    void update(int l, int r, int k, line cur)
    {
    	if(tree[k].l==tree[k].r-1)
    	{
    		if(tree[k].flag == 1 && cur.flag == 1)	tree[k].f = cur.x;
    		else if(tree[k].flag==2 && cur.flag==-1){
    			tree[k].x +=( cur.x - tree[k].f );
    			tree[k].f = 0.0;
    		}
    		tree[k].flag+=cur.flag;	
    		return;
    	}
    	int mi = (tree[k].l+tree[k].r)>>1;
    	if(l>=mi)	update(l,r,k+k+1,cur);
    	else if(r<=mi)	update(l,r,k+k,cur);
    	else{
    		update(l,mi,k+k,cur);
    		update(mi,r,k+k+1,cur);
    	}
    	return;
    }
    
    double query(int k)
    {
    	if(tree[k].l + 1==tree[k].r)	return (point[tree[k].r]-point[tree[k].l])*tree[k].x;
    	return query(k+k) + query(k+k+1);
    }
    
    int Ans()
    {
    	for(int i=1;i<xm;i++)
    	{
    		int x = Bin(x_line[i].y1);
    		int y = Bin(x_line[i].y2);
    		update(x,y,1,x_line[i]);
    	}
    }
    
    int main()
    {
    	int Case;
    	scanf("%d",&Case);
    	while(Case--)
    	{
    		memset(tree,0,sizeof(tree));
    		memset(point,-1,sizeof(point));
    		memset(x_line,0,sizeof(x_line));
    		Myscanf();
    		Point_Do();
    		Build(1,m,1);
    		Ans();
    		printf("%.2lf
    ",query(1));		
    	}
    
    	return 0;
    }
    

    主要思路就是将y轴离散为线段树,然后,将x轴转换为状态,其实也可以x为线段树,y为状态的


    版权声明:本文为博主原创文章,未经博主允许不得转载。

    本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    需要做一个 Android客户端 访问 服务器数据库 的 Demo
    如何使用Device File Explorer 从计算机拷贝文件到模拟器/手机?
    Android Studio 3.0 正式版 初体验
    Android Studio 原生模拟器, DDMS data打不开,adb shell 修改权限遇到:/system/bin/sh: su: not found
    2017.9.6 实验课:安装环境遇到的问题总结
    IntelliJ IDEA
    移动终端
    关于编程~
    2018面向对象程序设计(Java)第18周学习指导及要求
    2018面向对象程序设计(Java)第17周学习指导及要求
  • 原文地址:https://www.cnblogs.com/you-well-day-fine/p/4671650.html
Copyright © 2020-2023  润新知