简单的说就是从下到上扫描线段,累加记录该线段添加进去之后在总区间的映射有效长度*高度差。
线段树扫描线详解:矩形面积的并:http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html
矩形面积的交:http://www.cnblogs.com/scau20110726/archive/2013/04/14/3020998.html
看了这两篇博客+代码才有所理解。因为扫描的是线段,在线段树中分界点那部分区间可能无法表示,然后就变成了区间左闭右开[l,r),在更新的时候我们可以只更新闭区间即[l,r-1],在记录结果的时候把那个在加上。自己动手画图模拟会有更深的理解。
注意数据的离散化。。。
col[root]枚举到当前边的时候,下方有多少有用线段。(该区间矩形的下边比上边多几条)
即当前结点区间的覆盖情况,不必向下更新,当遇到矩形的上边的时候,直接更新当前结点。sum[root]区间被覆盖的长度
summ[root]区间被重复覆盖的长度/*注意更新*/
HDU 1542 【矩形面积的并】CODE:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
#define INF 0x3f3f3f3f
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
typedef long long LL;
using namespace std;
const int mod=998244353;
const int maxn=5005;
double sum[maxn<<2],X[maxn<<2];
int col[maxn<<2];
struct node
{
double l,r,h;
int s;
node() {};
node(double a,double b,double c,int d)
{
l=a,r=b,h=c;
s=d;
}
bool operator <(const node &cmp)const
{
return h<cmp.h;
}
}ss[maxn<<2];
void pushup(int l,int r,int root)
{
if(col[root])
sum[root]=X[r+1]-X[l];//*********
else if(l==r)
sum[root]=0;
else
sum[root]=sum[root<<1]+sum[root<<1|1];
}
void update(int L,int R,int c,int l,int r,int root)
{
if(L<=l&&r<=R)
{
col[root]+=c;
pushup(l,r,root);
return;
}
int m=(l+r)>>1;
if(L<=m)
update(L,R,c,lson);
if(R>m)
update(L,R,c,rson);
pushup(l,r,root);
}
int main()
{
int n,T=0;
while(~scanf("%d",&n)&&n)
{
int m=0,k=1;
double a,b,c,d;
for(int i=0;i<n;i++)
{
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
X[m]=a;
ss[m++]=node(a,c,b,1);
X[m]=c;
ss[m++]=node(a,c,d,-1);
}
sort(X,X+m);
sort(ss,ss+m);
for(int i=1;i<m;i++)
{
if(X[i]!=X[i-1])
X[k++]=X[i];
}
double ans=0;
memset(col,0,sizeof(col));
memset(sum,0,sizeof(sum));
for(int i=0;i<m-1;i++)
{
int l=lower_bound(X,X+k,ss[i].l)-X;
int r=lower_bound(X,X+k,ss[i].r)-X-1;//******
if(l<=r)
update(l,r,ss[i].s,0,k-1,1);
ans+=sum[1]*(ss[i+1].h-ss[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++T,ans);//注意格式
}
}
HDU 1225【矩形面积的交】 CODE:
summ[]数组的更新:1、col[root]>1,即该区间全部被覆盖了两次及两次以上,长度就是该区间的长度;
2、l==r最底层的叶子节点,无论覆盖没覆盖,都为0;
3、col[root]=1,左右子节点覆盖一次及一次以上的和(因为col[]没有向下更新,如果子区间有被 覆盖的,则就是被重复覆盖的);
4、其他,左右子节点覆盖两次及两次以上的和。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
#define INF 0x3f3f3f3f
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
typedef long long LL;
using namespace std;
const int mod=998244353;
const int maxn=5005;
double sum[maxn<<2],X[maxn<<2];
double summ[maxn<<2];
int col[maxn<<2];
struct node
{
double l,r,h;
int s;
node() {};
node(double a,double b,double c,int d)
{
l=a,r=b,h=c;
s=d;
}
bool operator <(const node &cmp)const
{
return h<cmp.h;
}
} ss[maxn<<2];
void pushup(int l,int r,int root)
{
if(col[root])
sum[root]=X[r+1]-X[l];
else if(l==r)
sum[root]=0;
else
sum[root]=sum[root<<1]+sum[root<<1|1];
if(col[root]>1)
summ[root]=X[r+1]-X[l];
else if(l==r)
summ[root]=0;
else if(col[root]==1)
summ[root]=sum[root<<1]+sum[root<<1|1];
else
summ[root]=summ[root<<1]+summ[root<<1|1];
}
void update(int L,int R,int c,int l,int r,int root)
{
if(L<=l&&r<=R)
{
col[root]+=c;
pushup(l,r,root);
return;
}
int m=(l+r)>>1;
if(L<=m)
update(L,R,c,lson);
if(R>m)
update(L,R,c,rson);
pushup(l,r,root);
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int m=0,k=1;
double a,b,c,d;
for(int i=0; i<n; i++)
{
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
X[m]=a;
ss[m++]=node(a,c,b,1);
X[m]=c;
ss[m++]=node(a,c,d,-1);
}
sort(X,X+m);
sort(ss,ss+m);
for(int i=1; i<m; i++)
{
if(X[i]!=X[i-1])
X[k++]=X[i];
}
double ans=0;
memset(col,0,sizeof(col));
memset(sum,0,sizeof(sum));
memset(summ,0,sizeof(summ));
for(int i=0; i<m-1; i++)
{
int l=lower_bound(X,X+k,ss[i].l)-X;
int r=lower_bound(X,X+k,ss[i].r)-X-1;
if(l<=r)
update(l,r,ss[i].s,0,k-1,1);
// cout<<l<<" "<<r<<"---"<<sum[1]<<endl;
ans+=summ[1]*(ss[i+1].h-ss[i].h);
}
printf("%.2lf\n",ans);
}
}