1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
using namespace std; const int N = 1005; struct edge { double l, r; double h; int f; bool operator<(const edge& temp)const { return h < temp.h; } }e[N<<1]; struct node { int l, r; int add; double len1, len2; }q[N<<3]; //n个矩形 n<<1个点 double x[N<<1];
void pushup(int i) { // pushup是当add有改变是就pushup //维护len1 if (q[i].add) //只要覆盖次数>=1,就更新len1 q[i].len1 = x[q[i].r + 1] - x[q[i].l]; else if (q[i].l == q[i].r) q[i].len1 = 0; else q[i].len1 = q[ls].len1 + q[rs].len1; //维护len2 if (q[i].add > 1) q[i].len2 = x[q[i].r + 1] - x[q[i].l];//右端+1直接算面积 else if (q[i].l == q[i].r) q[i].len2 = 0; //叶节点 else if (q[i].add == 1) //说明当前节点区间只被覆盖了1次,怎么算出覆盖超过2次的长度?找子区间 //但是子区间只要覆盖超过1次,那么也能求出该区间覆盖超过2次的长度 q[i].len2 = q[ls].len1 + q[rs].len1; else //如果该节点不是叶节点且覆盖次数为0,那么只能看子区间覆盖次数超过2次以上的长度了 q[i].len2 = q[ls].len2 + q[rs].len2; } void build(int i,int l,int r) { q[i].l = l; q[i].r = r; q[i].add = q[i].len1 = q[i].len2 = (double)0; if (l == r) return; int mid = (l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); } void update(int i,int l,int r,int val) {//1 -1 表示覆盖的次数.add存 if (l == q[i].l && r == q[i].r) { q[i].add += val; pushup(i); return; } int mid = (q[i].l + q[i].r) >> 1; if (r <= mid) update(ls,l,r,val); else if (l > mid) update(rs,l,r,val); else { update(ls,l,mid,val); update(rs,mid+1,r,val); } pushup(i); } int main() { //freopen("a.txt","r",stdin); int times; cin >> times; while (times--) { int n; scanf("%d",&n); int tot = 0; double x1, x2, y1, y2; for (int i = 1; i <= n; i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); edge& t1 = e[tot]; edge& t2 = e[tot + 1]; t1.l = t2.l = x1; t1.r = t2.r = x2; t1.h = y1; t1.f = 1; t2.h = y2; t2.f = -1; x[tot] = x1; x[tot + 1] = x2; tot += 2; } sort(x,x+tot); //给所有的浮点x坐标排序,离散化,使得他们在线段树中对应一个点 sort(e,e+tot); //给所有横边按高度排序 int k = 1; for (int i = 1; i < tot; i++) //去重,如果相同就跳过,将后面的复制给前面的 if (x[i] != x[i - 1]) x[k++] = x[i]; build(1,0,k-1); // k-1是`[]`的右端点 double ans = 0; for (int i = 0; i < tot; i++) { int l = lower_bound(x,x+k,e[i].l) - x; int r = lower_bound(x,x+k,e[i].r) - x - 1; update(1,l,r,e[i].f); ans += q[1].len2 * (e[i+1].h - e[i].h); } printf("%.2lf\n",ans); } return 0; }
|