题目分析
上次做了一道只用计算覆盖一次的面积,这次需要计算覆盖2次的面积,其实就是在上面的基础上加一点东西,sum1[]表示覆盖一次的长度,sum2[]覆盖2次的长度,具体怎么操作看pushup函数即可,写的非常清楚。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define mid (L+R)/2
#define lson o<<1, L, mid
#define rson o<<1|1, mid+1, R
const int maxn = 2005;
double pos[maxn<<2];
double sum1[maxn<<2], sum2[maxn<<2]; //sum1表示覆盖一次的长度,sum2表示覆盖2次的长度
int flag[maxn<<2];
struct Edge{
double l, r, h;
int f;
Edge(){}
Edge(double a, double b, double c, int d):l(a), r(b), h(c), f(d){}
bool operator < (const Edge& e)const{
return h < e.h;
}
}line[maxn];
void pushup(int o,int L,int R){ //这里代码已经写得很清楚了
if(flag[o]) sum1[o] = pos[R+1] - pos[L];
else if(L == R) sum1[o] = 0;
else sum1[o] = sum1[o<<1] + sum1[o<<1|1];
if(flag[o] > 1) sum2[o] = pos[R+1] - pos[L];
else if(L == R) sum2[o] = 0;
else if(flag[o] == 1) sum2[o] = sum1[o<<1] + sum1[o<<1|1];
else sum2[o] = sum2[o<<1] + sum2[o<<1|1];
}
void update(int o,int L,int R,int l,int r,int val){ //更新
if(l <= L && R <= r){
flag[o] += val;
pushup(o, L, R);
return;
}
if(l <= mid) update(lson, l, r, val);
if(r > mid) update(rson, l, r, val);
pushup(o, L, R);
}
int BS(double k, double a[], int len){ //二分查找
int L = 0, R = len-1;
while(L <= R){
if(a[mid] == k) return mid;
else if(a[mid] < k) L = mid+1;
else R = mid-1;
}
return -1;
}
int main(){
int T, n;
scanf("%d", &T);
while(T--){
memset(sum1, 0, sizeof(sum1));
memset(sum2, 0, sizeof(sum2));
memset(flag, 0, sizeof(flag));
memset(pos, 0, sizeof(pos));
double x1, y1, x2, y2;
scanf("%d", &n);
int k = 0;
for(int i = 0; i < n; i++){
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
pos[k] = x1;
line[k++] = Edge(x1, x2, y1, 1);
pos[k] = x2;
line[k++] = Edge(x1, x2, y2, -1);
}
sort(pos, pos+k);
sort(line, line+k);
int m = 1;
for(int i = 1; i < k; i++)
if(pos[i] != pos[i-1]) pos[m++] = pos[i];
double ans = 0;
for(int i = 0; i < k-1; i++){
int l = BS(line[i].l, pos, m);
int r = BS(line[i].r, pos, m)-1;
update(1, 0, k-1, l, r, line[i].f);
ans += sum2[1]*(line[i+1].h - line[i].h);
}
printf("%.2lf\n", ans);
}
return 0;
}