| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 18061 | Accepted: 6873 |
Description
Input
Output
Sample Input
2 10 10 20 20 15 15 25 25.5 0
Sample Output
Test case #1 Total explored area: 180.00
求矩形覆盖下的面积。可以把矩形平行y轴的线段都删去,这样就剩下很多平行x轴的线段。把线段y值按从小到大排序,每次插入一条线段得到当前覆盖在x轴的长度,乘以该条线段和下一条线段的z纵坐标之差,就是面积。求和即可。见下图
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
#define N 410
#define ll __int64
double x[N];
struct line //记录和x轴平行的线段信息
{
int f; //f为0、1代表为底边或顶边
double x1,x2,y; // 线段从左到右的端点,在y轴上的位置
}a[N];
struct node //线段树结构体
{
int f; //记录该区间是否重叠
double l,r,len; //记录区间的左右端点,和实际覆盖长度
}f[N*3];
bool cmp(line a,line b)
{
return a.y<b.y;
}
void creat(int t,int l,int r)
{
f[t].l=x[l];
f[t].r=x[r];
f[t].len=f[t].f=0;
if(l==r-1)
return ;
int tmp=t<<1,mid=(l+r)>>1;
creat(tmp,l,mid);
creat(tmp|1,mid,r); //线段是连续的,长度为f[t].r-f[t].l
}
void pushup(int t)
{
if(f[t].f)
f[t].len=f[t].r-f[t].l;
else
f[t].len=f[t<<1].len+f[t<<1|1].len;
}
void update(int t,line a)
{
if(f[t].l==a.x1&&f[t].r==a.x2)
{
f[t].f+=a.f;
pushup(t);
return ;
}
int tmp=t<<1;
if(a.x2<=f[tmp].r) //线段落在左边子区间
update(tmp,a);
else if(a.x1>=f[tmp|1].l) ////线段落在右边子区间
update(tmp|1,a);
else // 线段落在左右子区间
{
line b=a; //拆分线段为两段分属两个区间
b.x2=f[tmp].r;
update(tmp,b);
b=a;
b.x1=f[tmp].r;
update(tmp|1,b);
}
pushup(t); //向父节点求和
}
int main()
{
int i,n,cnt=1,m;
double x1,x2,y1,y2;
while(scanf("%d",&n),n)
{
for(i=m=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a[m].x1=x1;
a[m].x2=x2;
a[m].y=y1;
a[m].f=1;
x[m++]=x1;
a[m].x1=x1;
a[m].x2=x2;
a[m].y=y2;
a[m].f=-1;
x[m++]=x2;
}
sort(x+1,x+m); //排序
sort(a+1,a+m,cmp);
creat(1,1,m-1);
update(1,a[1]);
double ans=0;
for(i=2;i<m;i++)
{
ans+=f[1].len*(a[i].y-a[i-1].y);
update(1,a[i]);
}
printf("Test case #%d\n",cnt++);
printf("Total explored area: %.2f\n\n",ans);
}
return 0;
}
poj 1151 Atlantis (线段树+扫描线+离散化)
原文:http://blog.csdn.net/u011721440/article/details/41801145