Segment Tree 扫描线

#include<iostream>
#include<cstdio>
#include<algorithm> 
#define Max 1005
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(int 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(l==r-1)
	{
		if(tree[k].flag+cur.flag == 2)	tree[k].f = cur.x;
		else if(tree[k].flag+cur.flag<2 && cur.flag==-1){
			tree[k].x += cur.x - tree[k].f;
			tree[k].f = 0.0;
		}	
		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+1,r,k+k+1,cur);
	}
	return;
}

double query(int k)
{
	if(tree[k].l+1==tree[k].r)	return (point[tree[k].l]-point[tree[k].r])*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()
{
	Myscanf();
	Point_Do();
	Build(1,n,1);
	Ans();
	printf("%lf\n",query);
	return 0;
}
Code From Hdu 1542
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值