HDU-1264 Counting Squares 矩形面积并 线段树+扫描线

题意:

     给任意个矩形求矩形的并集

 

交集算的面积为覆盖一次或一次以上的面积

并集为覆盖两次或两次以上的面积 代码就多个求覆盖两次或两次的函数

可以参考矩形面积交

http://blog.csdn.net/u011742541/article/details/13233973

 

#include "stdio.h"
#include "algorithm"
using namespace std;
const int maxn = 110;
int n,pos;
int y[maxn*2];
struct node
{
	int x,y1,y2;
	int f;
}Line[maxn*2];

struct Node
{
	int y1,y2,len,inlen;
	int ld,rd,c;
}tree[maxn*4];

bool cmp( node a,node b )  
{  
   return a.x < b.x;  
} 
void swap( int &a,int &b )
{
	int temp = a;
	a = b;
	b = temp;
}

void buildtree( int ld,int rd,int t )
{
	tree[t].c = 0;		
	tree[t].y1 = y[ld]; tree[t].y2 = y[rd]; 
	tree[t].ld = ld;    tree[t].rd = rd;
	tree[t].len = 0;    tree[t].inlen = 0;
	if( ld + 1 == rd )
		return;
	int mid = ( ld+rd )>>1;
	buildtree( ld,mid,t<<1 );  
	buildtree( mid,rd,t<<1|1 );  
}
void calen( int t )             //求线段树被覆盖1次长度   
{  
    if( tree[t].c > 0 )   // t区间f是否被覆盖   
    {  
        tree[t].len = tree[t].y2 - tree[t].y1;  
        return;  
    }  
    if( tree[t].ld +1 == tree[t].rd ) tree[t].len = 0;      
    else  
        tree[t].len = tree[t<<1].len + tree[t<<1|1].len;    //  回带len的值   
}  
  
void incalen(int t)          //求交集时用到 线段被覆盖两次或两次以上   
{  
    if(tree[t].c >= 2)   
    {  
        tree[t].inlen = tree[t].y2 - tree[t].y1;  
        return;  
    }  
    if( tree[t].ld+1 == tree[t].rd )  tree[t].inlen = 0;  
    else if( tree[t].c == 1 )   
    {  
        tree[t].inlen = tree[t<<1].len + tree[t<<1|1].len;  
    }  
    else tree[t].inlen = tree[t<<1].inlen + tree[t<<1|1].inlen;  
} 

void updata( int t,node e )
{
	if( e.y1 == tree[t].y1 && e.y2 == tree[t].y2 )
	{
		tree[t].c += e.f;
		calen(t);  
		//incalen(t);			//求交集时用到
		return;
	}
	if( e.y2 <= tree[t<<1].y2 )
		updata( t<<1,e ); 
	else if( e.y1 >= tree[t<<1|1].y1 )  //e在tree[t]的右半边   
        updata( t<<1|1,e );  
	else
	{
		node temp = e;
		temp.y2 = tree[t<<1].y2;
		updata( t<<1,temp ); 

		temp = e;
		temp.y1 = tree[t<<1|1].y1;
		updata( t<<1|1,temp ); 
	}
	calen(t);  
    //incalen(t);					//求交集时用到
}

int main()
{
	//freopen( "data.txt","r",stdin );
    int x1,y1,x2,y2;
	while( true )
	{
		pos = 0;
		while( scanf("%d%d%d%d",&x1,&y1,&x2,&y2) == 4 && x1 != -1 && x1 != -2 )
		{
			if( x1 > x2 )               //把坐标1作为左上角 2作为右下角
				swap( x1,x2 );
			if( y1 > y2 )
				swap( y1,y2 );
			pos++;
			Line[pos].x = x1;       Line[pos].f = 1;
			Line[pos].y1 = y1;		Line[pos].y2 = y2;
			y[pos] = y1;
			
			pos++;
			Line[pos].x = x2;       Line[pos].f = -1;
			Line[pos].y1 = y1;		Line[pos].y2 = y2;
			y[pos] = y2;
			
		}
		sort( y+1,y+pos+1 );
		sort( Line+1,Line+pos+1,cmp );
		buildtree( 1,pos,1 );
		int ans = 0;
		for( int i = 1; i <= pos; i ++ )
		{
			ans += tree[1].len * ( Line[i].x - Line[i-1].x ); 
			updata( 1,Line[i] );  
		}
		printf("%d\n",ans);
		if( x1 == -2 )
			break;
	}
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值