这里介绍一个并不是很好理解的办法。
首先我们考虑将每个矩形的上下边进行拆解,然后排序进行扫描线。
如果我们令下边设成将对应横坐标区间都
+
1
+1
+1,上边设成对应横坐标区间
−
1
-1
−1。那么对于相邻两个边来说,我们就是要求高度差
×
\times
×权值大于1的横坐标区间长度。
考虑用线段树来维护这个过程,我们对横坐标进行离散化,然后对于线段树上的每个叶子节点,我们维护的是一个长度,长度是这个横坐标到下一个横坐标的长度。
然后每次对于修改的时候,进行一次区间修改即可
(
注
意
r
要
−
1
)
(注意r要-1)
(注意r要−1)
但是我们这时候会发现一个问题
我们没有办法直接维护一段区间的大于
1
1
1的长度,但是我们可以维护一个最小值的长度,然后用总长度,减去
0
0
0的长度,就能得到了!!!
for (int i=1;i<=cnt;i++) ymh=ymh+(x[i+1]-x[i]);
sum=sum+(ymh-query(1,1,cnt,1,cnt))*(a[i].h-lastans);
对于每一次 q u e r y query query,我们就可以直接询问区间最小值的个数。
db query(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y) return (f[root].ans)*(f[root].mn==0);
pushdown(root,l,r);
int mid =l+r >> 1;
db ans=0;
if(x<=mid) ans=ans+query(2*root,l,mid,x,y);
if (y>mid) ans=ans+query(2*root+1,mid+1,r,x,y);
return ans;
}
那么这个题大致上就这样解决了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
#define int long long
#define db double
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 5010;
struct Node{
int mn,len;
db ans;
};
struct qq{
db l,r;
db h,opt;
};
Node f[4*maxn];
int n,m;
db x[maxn],y[maxn];
int add[4*maxn];
qq a[maxn];
void init()
{
memset(f,0,sizeof(f));
memset(a,0,sizeof(a));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(add,0,sizeof(add));
}
void up(int root)
{
f[root].mn=min(f[2*root].mn,f[2*root+1].mn);
f[root].ans = (f[2*root].mn==f[root].mn)*f[2*root].ans;
f[root].ans += (f[2*root+1].mn==f[root].mn)*f[2*root+1].ans;
}
void pushdown(int root,int l,int r)
{
if (add[root])
{
add[2*root]+=add[root];
add[2*root+1]+=add[root];
f[2*root].mn+=add[root];
f[2*root+1].mn+=add[root];
add[root]=0;
}
}
bool cmp(qq a,qq b)
{
return a.h<b.h;
}
void build(int root,int l,int r)
{
if (l==r)
{
f[root].ans=x[l+1]-x[l];
f[root].mn=0;
return;
}
int mid = l+r >> 1;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
up(root);
}
void update(int root,int l,int r,int x,int y,int p)
{
if (x<=l && r<=y)
{
add[root]+=p;
f[root].mn+=p;
return;
}
pushdown(root,l,r);
int mid =l+r >> 1;
if (x<=mid) update(2*root,l,mid,x,y,p);
if (y>mid) update(2*root+1,mid+1,r,x,y,p);
up(root);
}
db query(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y) return (f[root].ans)*(f[root].mn==0);
pushdown(root,l,r);
int mid =l+r >> 1;
db ans=0;
if(x<=mid) ans=ans+query(2*root,l,mid,x,y);
if (y>mid) ans=ans+query(2*root+1,mid+1,r,x,y);
return ans;
}
signed main()
{
int uu=0;
while (1)
{
++uu;
init();
n=read();
if (n==0) break;
int cnt=0;
int tmp=0;
for (int i=1;i<=n;i++)
{
db b,c,d,e;
scanf("%lf%lf%lf%lf",&b,&c,&d,&e);
a[++tmp].h = c;
a[tmp].opt=1;
a[tmp].l=b;
a[tmp].r=d;
a[++tmp].h = e;
a[tmp].opt=-1;
a[tmp].l=b;
a[tmp].r=d;
x[++cnt]=b;
x[++cnt]=d;
}
sort(a+1,a+1+tmp,cmp);
sort(x+1,x+1+cnt);
int num = cnt;
cnt = unique(x+1,x+1+num) - x-1;
db ymh =0;
x[cnt+1]=x[cnt];
for (int i=1;i<=cnt;i++) ymh=ymh+(x[i+1]-x[i]);
build(1,1,cnt);
//cout<<f[1].ans<<endl;
db sum=0;
//cout<<ymh<<endl;
db lastans=a[1].h;
for (int i=1;i<=tmp;i++)
{
int l = lower_bound(x+1,x+1+cnt,a[i].l)-x;
int r = lower_bound(x+1,x+1+cnt,a[i].r)-x-1;
sum=sum+(ymh-query(1,1,cnt,1,cnt))*(a[i].h-lastans);
lastans=a[i].h;
update(1,1,cnt,l,r,a[i].opt);//cout<<sum<<" "<<query(1,1,cnt,1,cnt)<<" "<<l<<" "<<r<<endl;
}
printf("Test case #%d\n",uu);
printf("Total explored area: %.2f\n\n",sum);
//cout<<sum<<"\n";
}
return 0;
}