题目链接:点击打开链接
题目大意:
题目给你一些矩形的左下角坐标和右上角坐标,然后计算形成的新图形的面积。中间重叠的部分算作一部分。
题意解析:
要用到线段树扫描线的知识,从坐标系的下面往上面一次扫,每次维护当前高度的有效线段长。然后就可以通过高度差还有效线段长计算有效面积。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
struct node //记录线段左端点右端点和当前线段高度
{
double l,r,h;
int flag; //记录当前线段为上位边和下位边
bool operator<(const node &b) //通过线段高度对线段排序
{
return h<b.h;
}
}nodes[500000];
struct tree
{
int l,r,mid;
int cnt; //下位边减上位边的数
double sum; //本节点控制区域内cnt不为0的总长度
}t[500000];
int n;
double x[500000];
void pushdown(int rt) //从上到下维护
{
if(t[rt].cnt!=-1)
{
t[rt<<1].cnt=t[rt<<1|1].cnt=t[rt].cnt;
if(t[rt].cnt)
{
t[rt<<1].sum=x[t[rt].mid+1]-x[t[rt].l];
t[rt<<1|1].sum=x[t[rt].r+1]-x[t[rt].mid+1];
}
else
{
t[rt<<1].sum=0;
t[rt<<1|1].sum=0;
}
}
}
void pushup(int rt) //自上而下维护,cnt=-1代表当前区间左右儿子的上下位边数不同
{
if(t[rt<<1].cnt==-1||t[rt<<1|1].cnt==-1)
t[rt].cnt=-1;
else if(t[rt<<1].cnt!=t[rt<<1|1].cnt)
t[rt].cnt=-1;
else
t[rt].cnt=t[rt<<1].cnt;
t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
//printf("----%lf %d %lf %d\n",t[rt<<1].sum,t[rt<<1].l,t[rt<<1|1].sum,t[rt<<1|1].l);
}
void build(int l,int r,int rt)
{
if(l==r)
{
t[rt].l=t[rt].r=l;
t[rt].mid=(t[rt].l+t[rt].r)/2;
t[rt].cnt=0;
t[rt].sum=0.0;
return ;
}
int mid=(l+r)/2;
t[rt].l=l;
t[rt].r=r;
t[rt].mid=mid;
t[rt].cnt=0;
t[rt].sum=0.0;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
void update(int l,int r,int flag,int rt) //更新结果
{
if(t[rt].l>=l&&t[rt].r<=r)
{
if(t[rt].cnt!=-1)
{
t[rt].cnt=t[rt].cnt+flag;
if(t[rt].cnt)
t[rt].sum=x[t[rt].r+1]-x[t[rt].l];
else
t[rt].sum=0;
return ;
}
}
pushdown(rt);
if(l<=t[rt].mid)
update(l,r,flag,rt<<1);
if(r>t[rt].mid)
update(l,r,flag,rt<<1|1);
pushup(rt);
}
int bin(double key,int n,double d[])
{
int l=1,r=n;
while(l<=r)
{
int m=(l+r)/2;
if(d[m]==key)
return m;
else if(d[m]>key)
r=m-1;
else
l=m+1;
}
return -1;
}
int main()
{
int kase=0;
while(scanf("%d",&n)!=EOF)
{
int gg=0;
if(n==0)
break;
for(int i=0;i<n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
x[++gg]=x1;
nodes[gg].l=x1;
nodes[gg].r=x2;
nodes[gg].h=y1;
nodes[gg].flag=1;
x[++gg]=x2;
nodes[gg].l=x1;
nodes[gg].r=x2;
nodes[gg].h=y2;
nodes[gg].flag=-1;
}
sort(x+1,x+gg+1);
sort(nodes+1,nodes+gg+1);
int k=1;
for(int i=2;i<=gg;i++)
{
if(x[i-1]!=x[i])
x[++k]=x[i];
}
build(1,k-1,1); //用每个节点代表一段区间
double ans=0.0;
for(int i=1;i<gg;i++)
{
int l=bin(nodes[i].l,k,x);
int r=bin(nodes[i].r,k,x)-1;
if(l<=r)
update(l,r,nodes[i].flag,1);
//printf("%lf\n",t[1].sum);
ans=ans+t[1].sum*(nodes[i+1].h-nodes[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ans);
}
}