poj1151 Atlantis(线段树+离散化+扫描线)

题意:给出一堆坐标,问最后构成的面积有多少(重复的面积只能算一次)

思路:首先,这道题的数据量完全可以暴力过的,但是下面这么做只是想练练线段树和离散化的结合。给出的坐标不是整数,所以可以这么做。把各个x,从小到大扫描,然后对所有y值进行离散化,给其一个整数标号,这样y就可以用线段树进行维护了。然后没扫描一条x纵线就决定是从线段树中去除还是增加那一条线段,然后算面积。

#include<cstdio> 
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node1
{
	double x,y1,y2;
	int fg;
	node1(double x,double y1,double y2,int fg):x(x),y1(y1),y2(y2),fg(fg){}
};
struct node2
{
	double l,r,sum;
	int num;
}s[100000];
vector<node1> s1;
int n;
double y[1000];
bool cmp(node1 a,node1 b)
{
	return a.x<b.x;
}
void make_tree(int root,int l,int r)
{
	//cout<<root<<" "<<l<<" "<<r<<endl;
	s[root].l=y[l];
	s[root].r=y[r];
	s[root].sum=0;
	s[root].num=0;
	if(r-l<=1) return;
	int mid=(l+r)/2;
	make_tree(root*2,l,mid);
	make_tree(root*2+1,mid,r);
}
void push_up(int root)
{
    if( s[root].num>0 )
        s[root].sum = s[root].r - s[root].l ;
    else
        s[root].sum = s[2*root].sum + s[2*root+1].sum ;
}

void update(int root,int fg,double l,double r)
{
	if(s[root].l==l&&s[root].r==r)
	{
		s[root].num+=fg;
		push_up(root);
		return;
	}
	if(s[root*2].r>l)
	{
		update(root*2,fg,l,min(r,s[root*2].r));
	}
	if(s[root*2+1].l<r)
	{
		update(2*root+1,fg,max(s[root*2+1].l,l),r);
	}
	push_up(root);
	
}
int main()
{
	//freopen("t.txt","r",stdin);
	double x1,y1,x2,y2;
	int cnt=1;
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0) break;
		memset(s,0,sizeof(s));
		s1.clear();
		for(int i=0;i<n;i++)
		{
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			s1.push_back(node1(x1,y1,y2,1));
			s1.push_back(node1(x2,y1,y2,-1));
			y[2*i+1]=y1;
			y[2*i+2]=y2;
		}
		sort(s1.begin(),s1.end(),cmp);
		sort(y+1,y+1+2*n);
		make_tree(1,1,2*n);
		update(1,s1[0].fg,s1[0].y1,s1[0].y2);
		double sum=0;
		for(int i=1;i<2*n;i++)
		{
			sum+=(s1[i].x-s1[i-1].x)*s[1].sum;
			update(1,s1[i].fg,s1[i].y1,s1[i].y2);
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n",cnt++,sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39861441/article/details/83826439
今日推荐