zoukankan      html  css  js  c++  java
  • 线段树扫描线(二)矩形周长 以hdu1828为例

    还是老规矩,传送门 hdu 1828

     依然不做过多解释,给出n个矩形,求这些矩形组合而成的图形的周长(中间镂空的部分也算)

    还是像扫面线(一)一样,自下而上扫描,

    我们先只考虑横线,发现只要每次加上被覆盖的区间长度的变化值的绝对值就能统计出横向的答案,

    但竖线怎么办?

    有一种朴素的办法,自下而上扫过一次后,从左到右在扫一遍,常数问题(好像不卡)

    接下来,讲一种更好的办法。

    我所说的办法,就是在自下而上扫描时,同时统计出竖线的长度和。

    每条竖线的长度很好统计,用这一条扫描线的高度减去上一条扫描线的的高度即可,但有多少条竖线呢?

    我们可以在线段树中添加三个成员,这样总共就会有五个:

    struct node
    {
          int dis;  //被覆盖的长度
          int cnt;  //被整体覆盖了几次
          int ls;   //左端点是否被覆盖
          int rs;   //右端点是否被覆盖
          int num;  //区间中总共有多少条竖线
    };

    接下来,考虑pushup()要怎么写

    更新dis的部分在此不再赘述,详见最下面代码或者 扫描线(一)

    正确的更新竖线的代码是这样的

    tre[nc].ls=tre[2*nc].ls;
    tre[nc].rs=tre[2*nc+1].rs;
    tre[nc].num=tre[2*nc].num+tre[2*nc+1].num;
    if(tre[2*nc].rs&&tre[2*nc+1].ls)
    {
        tre[nc].num-=2;  
    }

    关键点在if里边,画张图

     如图所示,L到R的的两个子区间中,有两条竖线在和并之后消失了,其原因是这两条线段刚好覆盖了分点,因而,要加上if来保证其正确性

    然后就是一个小细节,重边要先加后减,否则就会多统计重边,排序时在cmp中处理一下即可。

    奉上代码

      1 #include<cstdio>
      2 #include<map>
      3 #include<algorithm>
      4 #include<cstring>
      5 using namespace std;
      6 map<int,int> mp;
      7 int ls[20100],x1,x2,y1,y2;
      8 int n,cnt,cd;
      9 struct edge
     10 {
     11     int l,r,val,h;
     12 }eds[10100];
     13 struct node
     14 {
     15     int cov,dis,ls,rs,num;
     16 }tre[80100];
     17 int cmp(edge a,edge b)
     18 {
     19     if(a.h==b.h)
     20     {
     21         return a.val>b.val;
     22     }
     23     return a.h<b.h;
     24 }
     25 int fabs(int a){return a>0?a:-a;}
     26 void init()
     27 {
     28     cnt=1;
     29     cd=1;
     30     mp.clear();
     31     memset(ls,0,sizeof(ls));
     32 }
     33 int fd(int tar)
     34 {
     35     int l=1,r=cd;
     36     while(l<r)
     37     {
     38         int mid=(l+r)/2;
     39         if(ls[mid]<tar)
     40         {
     41             l=mid+1;
     42         }
     43         else
     44         {
     45             r=mid;
     46         }
     47     }
     48     return l;
     49 }
     50 void pushup(int L,int R,int nc)
     51 {
     52     if(tre[nc].cov)
     53     {
     54         tre[nc].dis=ls[R+1]-ls[L];
     55         tre[nc].num=2;
     56     }
     57     else
     58     {
     59         if(L==R)
     60         {
     61             tre[nc].dis=0;
     62             tre[nc].ls=0;
     63             tre[nc].rs=0;
     64             tre[nc].num=0;
     65         }
     66         else
     67         {
     68             tre[nc].dis=tre[2*nc].dis+tre[2*nc+1].dis;
     69             tre[nc].num=tre[2*nc].num+tre[2*nc+1].num;
     70             if(tre[2*nc].rs&&tre[2*nc+1].ls)
     71             {
     72                 tre[nc].num-=2;
     73             }
     74             tre[nc].ls=tre[2*nc].ls;
     75             tre[nc].rs=tre[2*nc+1].rs;
     76         }
     77     }
     78 }
     79 void ins(int l,int r,int dt,int nc,int L,int R)
     80 {
     81     if(l<=L&&r>=R)
     82     {
     83         tre[nc].cov+=dt;
     84         tre[nc].ls+=dt;
     85         tre[nc].rs+=dt;
     86         if(tre[nc].cov)
     87         {
     88             tre[nc].dis=ls[R+1]-ls[L];
     89             tre[nc].num=2;
     90         }
     91         else
     92         {
     93             if(L==R)
     94             {
     95                 tre[nc].dis=0;
     96                 tre[nc].ls=0;
     97                 tre[nc].rs=0;
     98                 tre[nc].num=0;
     99             }
    100             else
    101             {
    102                 tre[nc].num=tre[2*nc].num+tre[2*nc+1].num;
    103                 if(tre[2*nc].rs&&tre[2*nc+1].ls)
    104                 {
    105                     tre[nc].num-=2;
    106                 }
    107                 tre[nc].ls=tre[2*nc].ls;
    108                 tre[nc].rs=tre[2*nc+1].rs;
    109                 tre[nc].dis=tre[2*nc].dis+tre[2*nc+1].dis;
    110             }
    111         }
    112         return;
    113     }
    114     int mid=(L+R)/2;
    115     if(l<=mid)
    116     {
    117         ins(l,r,dt,2*nc,L,mid);
    118     }
    119     if(r>mid)
    120     {
    121         ins(l,r,dt,2*nc+1,mid+1,R);
    122     }
    123     pushup(L,R,nc);
    124 }
    125 int main()
    126 {
    127     while(scanf("%d",&n)!=EOF)
    128     {
    129         init();
    130         for(int i=1;i<=n;i++)
    131         {
    132             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    133             eds[cnt].h=y1;
    134             eds[cnt].l=x1;
    135             eds[cnt].r=x2;
    136             eds[cnt].val=1;
    137             cnt++;
    138             eds[cnt].h=y2;
    139             eds[cnt].l=x1;
    140             eds[cnt].r=x2;
    141             eds[cnt].val=-1;
    142             cnt++;
    143             if(!mp[x1])
    144             {
    145                 mp[x1]=1;
    146                 ls[cd]=x1;
    147                 cd++;
    148             }
    149             if(!mp[x2])
    150             {
    151                 mp[x2]=1;
    152                 ls[cd]=x2;
    153                 cd++;
    154             }
    155         }
    156         sort(ls+1,ls+cd);
    157         for(int i=1;i<cnt;i++)
    158         {
    159             eds[i].l=fd(eds[i].l);
    160             eds[i].r=fd(eds[i].r);
    161         }
    162         sort(eds+1,eds+cnt,cmp);
    163         ins(eds[1].l,eds[1].r-1,eds[1].val,1,1,cd-1);
    164         int last=eds[1].h,ans=tre[1].dis,lasa=ans;
    165         for(int i=2;i<cnt;i++)
    166         {
    167             int n0=tre[1].num;
    168             ins(eds[i].l,eds[i].r-1,eds[i].val,1,1,cd-1);
    169             ans+=fabs(tre[1].dis-lasa);
    170             ans+=(eds[i].h-last)*n0;
    171             lasa=tre[1].dis;
    172             last=eds[i].h;
    173         }
    174         printf("%d
    ",ans);
    175     }
    176 }

    大家可能会发现这和(一)中的代码神似,没错,鄙人就是根据(一)中的代码加以修改的!!!!!!!!!!!!!!!

  • 相关阅读:
    使用NDK编译 libyuv <转>
    x264中重要结构体参数解释,参数设置,函数说明 <转>
    x264的一些参数设置对编码效率的影响
    首都儿研所开钙片!!!
    Android 媒体编解码器(转)
    opengl版本和扩展
    ffmpeg一揽子
    Android 使用SWIG生成Jni代码<转>
    CF 19D 线段树+set压缩坐标轴+离散化map
    android4.0 FaceDetection笔记
  • 原文地址:https://www.cnblogs.com/Grharris/p/10392495.html
Copyright © 2011-2022 走看看