题意:n个矩形求出被两个以上矩形覆盖的面积之和
第一种方法每次都查找到最底层的节点,并计算其对总面积的贡献。这样比较好想也比较好写,但是比较慢,差不多要1s。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ld d<<1
#define rd d<<1|1
const int N = 2005;
double y[N<<2];
struct seg
{
double x, y1,y2;
int flag;
bool operator <(const seg a) const
{
return x < a.x;
}
}a[N<<2];
struct node
{
double x;
int cover;
}tr[N << 3];
void build(int d, int l, int r)
{
tr[d].x = -1;
tr[d].cover = 0;
if(r - l == 1) return;
int m = (l+r) >>1;
build(ld,l,m); build(rd,m,r);
return;
}
double query(int d, int l, int r, double ql,double qr, double x, int fl)
{
double ans = 0;
if(r - l == 1)
{
if(tr[d].cover >= 2) ans = (y[r] - y[l])*(x - tr[d].x);
tr[d].x = x; tr[d].cover += fl;
return ans ;
}
int m = (l+r) >>1;
if(ql < y[m]) ans += query(ld,l,m,ql,qr,x,fl);
if(y[m] < qr) ans += query(rd,m,r,ql,qr,x,fl);
return ans;
}
int main()
{
int times; scanf("%d",×);
while(times --)
{
int n; scanf("%d",&n);
int k = 0;
for(int i = 0; i < n; i++)
{
double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a[k].x = x1,a[k].y1 = y1,a[k].y2 = y2; a[k].flag = 1;y[k++] = y1;
a[k].x = x2,a[k].y1 = y1,a[k].y2 = y2; a[k].flag = -1; y[k++] = y2;
}
sort(y,y+k);
sort(a,a+k);
int cony = unique(y,y+k) - y;
build(1,0,cony - 1);
double ans = 0;
for(int i = 0; i < k; i++)
{
ans += query(1,0,cony - 1,a[i].y1,a[i].y2,a[i].x,a[i].flag);
}
printf("%.2f\n",ans);
}
}
第二种方法,每次查找到待插入的区间就不往下继续查找了,节点的len保存已经被覆盖两次以上的区间的总长度,所以只需要用本次更新前的根节点的len值,和上次插入的边的x值进行计算,即可算出本次操作的贡献值。这个方法会稍微快一些,因为不需要每次都递归到最深层,只需要在递归返回的过程中依次维护父节点的值就好,用时在300ms以内。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ld d<<1
#define rd d<<1|1
const int N = 2005;
double y[N<<2];
struct seg
{
double x, y1,y2;
int flag;
bool operator <(const seg a) const
{
return x < a.x;
}
}a[N<<2];
struct node
{
double x,len,telen;
int cover;
}tr[N << 3];
void build(int d, int l, int r)
{
tr[d].x = -1;
tr[d].cover = 0;
if(r - l == 1) return;
int m = (l+r) >>1;
build(ld,l,m); build(rd,m,r);
return;
}
void update(int d, int l, int r)
{
if(tr[d].cover >= 2)
{
tr[d].len = y[r] - y[l];
tr[d].telen = 0;
return ;
}
if(tr[d].cover == 1)
{
if(r - l == 1) tr[d].len = 0;
else tr[d].len = tr[ld].len + tr[rd].len+tr[ld].telen + tr[rd].telen;
tr[d].telen = y[r] - y[l] - tr[d].len;
return ;
}
if(tr[d].cover == 0)
{
if(r - l == 1) tr[d].len = tr[d].telen = 0;
else
tr[d].telen = tr[ld].telen + tr[rd].telen,tr[d].len = tr[ld].len + tr[rd].len;
}
}
void query(int d, int l, int r, double ql,double qr, double x, int fl)
{
if(ql <= y[l] && y[r] <= qr)
{
tr[d].cover += fl;
update(d,l,r);
return ;
}
if(r - l == 1) return ;
int m = (l+r) >>1;
if(ql < y[m])query(ld,l,m,ql,qr,x,fl);
if(y[m] < qr)query(rd,m,r,ql,qr,x,fl);
update(d,l,r);
return ;
}
int main()
{
int times; scanf("%d",×);
while(times --)
{
int n; scanf("%d",&n);
int k = 0;
for(int i = 0; i < n; i++)
{
double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a[k].x = x1,a[k].y1 = y1,a[k].y2 = y2; a[k].flag = 1;y[k++] = y1;
a[k].x = x2,a[k].y1 = y1,a[k].y2 = y2; a[k].flag = -1; y[k++] = y2;
}
sort(y,y+k);
sort(a,a+k);
int cony = unique(y,y+k) - y;
build(1,0,cony - 1);
double ans = 0.0;
double lalen = 0;
for(int i = 0; i < k; i++)
{
query(1,0,cony - 1,a[i].y1,a[i].y2,a[i].x,a[i].flag);
if(i >= 1)
{
ans += lalen *(a[i].x - a[i -1].x);
}
lalen = tr[1].len;
}
printf("%.2f\n",ans);
}
}