题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
思路: 与扫描线求面积并类似。在面积并的基础上 多增加一个 sum2[] 数组,存放覆盖两次及以上的投影。具体看代码
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 2220;
struct xx{
double l,r,h;
int d;
xx(){}
xx(double l,double r,double h,int d):l(l),r(r),h(h),d(d){}
}line[maxn];
double sum[maxn << 2];
double sum2[maxn << 2];
double x[maxn];
int cnt[maxn << 2];
bool cmp(xx A, xx B){
return A.h < B.h;
}
///两个pushup函数也可以写为一个
void pushup(int l,int r,int i){
if(cnt[i]) sum[i] = x[r+1] - x[l];
else if(l == r) sum[i] = 0;
else sum[i] = sum[i<<1] + sum[i<<1|1];
}
void pushup2(int l,int r,int i){
if(cnt[i] > 1) ///如果当前结点区间已经是第二次或以上被覆盖 直接算出其投影长度
sum2[i] = x[r+1] - x[l];
else if(cnt[i] == 1) ///如果 == 1 , 则等于子区间被覆盖过一次的线段长度之和
sum2[i] = sum[i<<1] + sum[i<<1|1];
else if(l == r) ///显然,叶子节点 == 0.
sum2[i] = 0;
else sum2[i] = sum2[i<<1] + sum2[i<<1|1]; ///若整体没被标记过,则等于子区间被覆盖过俩次的线段长度之和
}
/*
void build(int l,int r,int i){
sum[i] = cnt[i] = sum2[i] = 0;
if(l == r) return ;
int mid = (l + r) >> 1;
build(l,mid,i << 1);
build(mid + 1,r,i << 1 | 1);
}
*/
void update(int l,int r,int ul,int ur,int key,int i){
if(ul <= l && r <= ur){
cnt[i] += key;
pushup(l,r,i);
pushup2(l,r,i);
return ;
}
int mid = (l + r) >> 1;
if(ul <= mid) update(l,mid,ul,ur,key,i << 1);
if(ur > mid) update(mid + 1,r,ul,ur,key,i << 1 | 1);
pushup(l,r,i);
pushup2(l,r,i);
}
int main()
{
int t; scanf("%d",&t);
int n;
while(t--){
scanf("%d",&n);
int pl = 1;
double x1,x2,y1,y2;
for(int i = 0;i < n;i ++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[pl] = xx(x1,x2,y1,1);
x[pl ++] = x1;
line[pl] = xx(x1,x2,y2,-1);
x[pl ++] = x2;
}
sort(line + 1,line + pl,cmp);
sort(x + 1,x + pl);
int m = unique(x + 1,x + pl) - x - 1;
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
memset(sum2,0,sizeof(sum2));
double ans = 0;
for(int i = 1;i < pl;i ++){
int l = lower_bound(x + 1,x + m + 1,line[i].l) - x;
int r = lower_bound(x + 1,x + m + 1,line[i].r) - x - 1;
update(1,m,l,r,line[i].d,1);
ans += sum2[1] * (line[i+1].h - line[i].h);
}
printf("%.2lf\n",ans);
}
return 0;
}