pku1177 Picture

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

转载于:https://www.cnblogs.com/zgmf_x20a/archive/2008/10/17/1313635.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值