思路:
1,对y坐标离散化,设有ycnt个不同的y值,在[0,ycnt]上建立线段树
2,建立竖边结构(每个矩形有两条竖边,n个矩形有2*n条竖边):
struct Edge{
int yu;//竖边上端点y坐标
int yd;//下端点y坐标
int x;//x坐标
int tag;//竖边类型
}
把所有竖边分为IN和OUT两类,再对x排序,扫描线遇到IN则对线段树插入[yd,yu],遇到OUT则删除[yd,yu],注意只有曾经插入过的区间才能够进行删除
3,说说线段树的结点:
struct Node{
int l,r;//区间
int cnt;//计数器
int nseg,nlen;//扫描线被矩形覆盖的部分的段数和长度
bool lc,rc;//若该区间左右端点是否被覆盖的标记
}
设xans和yans分别为竖轮廓和横轮廓的长度,root'和root分别记录了扫描线在位置x1和x2时区间[0,ycnt]的信息,若扫描线从x1扫描至x2,则xans和yans有如下变化:
xans+=root'.nseg*2*(x2-x1);
yans+=abs(root.nlen-root'.nlen);
另外,在插入和删除操作中要注意对线段树结点信息的维护
#include
<
iostream
>
#include
<
algorithm
>
using
namespace
std;
#define
IN 1
#define
OUT 0
#define
MAXN 10001
#define
clr(x) memset(x,0,sizeof(x));
int
n,ycnt,yinterval[
2
*
MAXN],yans,xans;
//
yinterval[i]=y表示纵坐标经过排序后第i个不同的纵坐标为y
int
sy[
2
*
MAXN];
//
sy[y]=i表示纵坐标经过排序后y是第i小的纵坐标,与yinterval[i]=y互为反函数
struct
Edge{
int
yu,yd,x,tag;
}e[
2
*
MAXN];
struct
Node{
int
l,r;
int
cnt;
int
nseg,nlen;
bool
lc,rc;
}nod[
3
*
MAXN];
class
CP{
public
:
int
operator
()(Edge
&
arg1,Edge
&
arg2){
return
arg1.x
<
arg2.x;
}
};
void
buildtree(
int
v,
int
l,
int
r){
nod[v].l
=
l;
nod[v].r
=
r;
nod[v].lc
=
nod[v].rc
=
false
;
nod[v].nlen
=
nod[v].nseg
=
0
;
nod[v].cnt
=
0
;
if
(r
-
l
==
1
)
return
;
buildtree(
2
*
v,l,(l
+
r)
/
2
);
buildtree(
2
*
v
+
1
,(l
+
r)
/
2
,r);
}
void
init(){
int
i,xl,xr,yu,yd;
ycnt
=
0
;
clr(sy);
for
(i
=
0
;i
<
n;i
++
){
scanf(
"
%d%d%d%d
"
,
&
xl,
&
yd,
&
xr,
&
yu);
e[
2
*
i].yu
=
yu;
e[
2
*
i].yd
=
yd;
e[
2
*
i].x
=
xl;
e[
2
*
i].tag
=
IN;
e[
2
*
i
+
1
].yu
=
yu;
e[
2
*
i
+
1
].yd
=
yd;
e[
2
*
i
+
1
].x
=
xr;
e[
2
*
i
+
1
].tag
=
OUT;
if
(
!
sy[yd]){
yinterval[ycnt
++
]
=
yd;
sy[yd]
=
1
;
}
if
(
!
sy[yu]){
yinterval[ycnt
++
]
=
yu;
sy[yu]
=
1
;
}
}
sort(yinterval,yinterval
+
ycnt);
for
(i
=
0
;i
<
ycnt;i
++
)
sy[yinterval[i]]
=
i;
sort(e,e
+
2
*
n,CP());
buildtree(
1
,
0
,ycnt
-
1
);
}
void
insert(
int
v,
int
l,
int
r){
if
(l
<=
nod[v].l
&&
nod[v].r
<=
r){
nod[v].nlen
=
yinterval[nod[v].r]
-
yinterval[nod[v].l];
nod[v].cnt
++
;
nod[v].nseg
=
1
;
nod[v].lc
=
true
;
nod[v].rc
=
true
;
return
;
}
if
(l
<
nod[
2
*
v].r)
insert(
2
*
v,l,r);
if
(r
>
nod[
2
*
v
+
1
].l)
insert(
2
*
v
+
1
,l,r);
if
(nod[v].cnt
==
0
){
nod[v].lc
=
nod[
2
*
v].lc;
nod[v].rc
=
nod[
2
*
v
+
1
].rc;
nod[v].nlen
=
nod[
2
*
v].nlen
+
nod[
2
*
v
+
1
].nlen;
nod[v].nseg
=
nod[
2
*
v].nseg
+
nod[
2
*
v
+
1
].nseg;
if
(nod[
2
*
v].rc
&&
nod[
2
*
v
+
1
].lc)
nod[v].nseg
--
;
}
}
void
del(
int
v,
int
l,
int
r){
if
(l
<=
nod[v].l
&&
nod[v].r
<=
r){
nod[v].cnt
--
;
if
(nod[v].cnt
==
0
){
if
(nod[v].r
-
nod[v].l
==
1
){
nod[v].lc
=
nod[v].rc
=
false
;
nod[v].nlen
=
nod[v].nseg
=
0
;
}
else
{
nod[v].lc
=
nod[
2
*
v].lc;
nod[v].rc
=
nod[
2
*
v
+
1
].rc;
nod[v].nlen
=
nod[
2
*
v].nlen
+
nod[
2
*
v
+
1
].nlen;
nod[v].nseg
=
nod[
2
*
v].nseg
+
nod[
2
*
v
+
1
].nseg;
if
(nod[
2
*
v].rc
&&
nod[
2
*
v
+
1
].lc)
nod[v].nseg
--
;
}
}
return
;
}
if
(l
<
nod[
2
*
v].r)
del(
2
*
v,l,r);
if
(r
>
nod[
2
*
v
+
1
].l)
del(
2
*
v
+
1
,l,r);
if
(nod[v].cnt
==
0
){
nod[v].lc
=
nod[
2
*
v].lc;
nod[v].rc
=
nod[
2
*
v
+
1
].rc;
nod[v].nlen
=
nod[
2
*
v].nlen
+
nod[
2
*
v
+
1
].nlen;
nod[v].nseg
=
nod[
2
*
v].nseg
+
nod[
2
*
v
+
1
].nseg;
if
(nod[
2
*
v].rc
&&
nod[
2
*
v
+
1
].lc)
nod[v].nseg
--
;
}
}
void
cal(){
yans
=
0
;
xans
=
0
;
int
i;
insert(
1
,sy[e[
0
].yd],sy[e[
0
].yu]);
yans
=
nod[
1
].nlen;
memcpy(nod,nod
+
1
,
sizeof
(nod[
0
]));
for
(i
=
1
;i
<
2
*
n;i
++
){
if
(e[i].tag
==
IN)
insert(
1
,sy[e[i].yd],sy[e[i].yu]);
else
del(
1
,sy[e[i].yd],sy[e[i].yu]);
yans
+=
abs(nod[
1
].nlen
-
nod[
0
].nlen);
xans
+=
2
*
nod[
0
].nseg
*
(e[i].x
-
e[i
-
1
].x);
memcpy(nod,nod
+
1
,
sizeof
(nod[
0
]));
}
}
int
main(){
while
(scanf(
"
%d
"
,
&
n)
!=
EOF){
init();
cal();
printf(
"
%d\n
"
,yans
+
xans);
}
return
0
;
}