思路:
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 < 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 ;
}