题意:给出一堆坐标,问最后构成的面积有多少(重复的面积只能算一次)
思路:首先,这道题的数据量完全可以暴力过的,但是下面这么做只是想练练线段树和离散化的结合。给出的坐标不是整数,所以可以这么做。把各个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;
}