zoukankan      html  css  js  c++  java
  • 线段树小结

     1  线段树小结篇:
     2  基本是按着HH专辑来练的:http://www.notonlysuccess.com/index.php/segment-tree-complete/
     3  按分类为单点更新,成段更新,区间合并,扫描线;
     4  做了一些题目,显然对于明显的操作如单纯的单点更新,敲出代码是不成问题的;
     5  但对于稍微麻烦一点的操作,如果没有很好的代码能力和平时的积累,就很难在比赛时一气呵成写出代码;
     6  因此写本文在于总结线段树代码的一些细节之处,给自己以后遗忘复习用;
     7  
     8  1:lazy标记;
     9     lazy标记主要运用于成段更新时,这也是线段树经常用到的,因为每次更新只需要更新到当前位置,
         等到下次更新或者询问时再更新,使得更新的复杂度降低。
    10   lazy标记对于初写线段数的人来说是个不小的挑战,刚开始写成段更新时,可能会遇到的问题: 11 a:lazy标记是对于当前节点rt来说,还是对于子节点rt<<1,rt<<1|1来说,
    即对当前col[rt],当pushdown(rt)时,
    是更新rt节点的值,还是更新子节点的值? 14 b: 在update()时,lazy标记会被更新,此时要不要对当前rt更新值? 15 16 这些问题主要是因为当时不明白lazy标记到底表示的是什么意思; 17 col[rt]的含义: col[rt]标记为空; 18 col[rt]不为空: 当前段被标记,
                     当update(),query()到当前段是,要先pushdown()下去,再递归到子节点;
    19 21 lazy标记的精髓就在于延迟操作,但提前是延迟操作不会使结果不正确,那为什么不会使结果不正确呢? 22 因为线段树操作不管是update(),query()都是从根节点开始的,
           当询问或更新到需要的当前段后,已经完成了操作,
    23 24 我们直接从该段pushup()上去,不会导致最终解错误,对于该段的子段来说我们不需要它的解,
                 所以我们把这些我们当前不需要的段不进行更新,
    25 26 用lazy标记记录下来, 当需要的时候先把它更新了,再进行必要操作; 27 28 也就是col[rt]不为空时,它只对子节点产生影响,
                 并且col[rt]不为空时,sum[rt],cnt[rt],rt节点的值都是正确的,在pushudown()时,
    29 30           把标记传给col[rt<<1]和col[rt<<1|1],所以rt<<1,和rt<<1|1的值就要更新,
                col[rt]已经把标记传下去了,所以要清空;
    在update()时,被标记的当前段也要更新为正确值;

             http://acm.hdu.edu.cn/showproblem.php?pid=3397

        

    View Code

      2:离散化的一些细节;

      a:对于数据范围超过10^6,和double类型的数据都要进行离散化,但离散化后一般会遇到一些问题,
      线段树里的一个节点代表的是一段距离,但离散后一个点就是一个点;比如更新(1,3),会更新到(1,2)(3,3)
      如果单纯的计算距离的会3-3=0,so在更新的时候要处理一下更新(1,3),传入的值为(1,2)然后在计算距离是用xi[3]-xi[1]

      b:原先代表是一段区域;

      c:要考虑端点和中间,要乘2;

      1 //hdu3397
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<iostream>
      6 #include<cmath>
      7 #include<algorithm>
      8 #define lson l,m,rt<<1
      9 #define rson m+1,r,rt<<1|1
     10 using namespace std;
     11 const int MAXN=111111;
     12 int mx_0[MAXN<<2];//改段连续0的个数
     13 int mx_1[MAXN<<2];//该段连续1的个数
     14 int conl_1[MAXN<<2],conr_1[MAXN<<2];//左边连续1的个数,右边连续1的个数
     15 int conl_0[MAXN<<2],conr_0[MAXN<<2];//同上
     16 int cnt[MAXN<<2];//记录该段1的个数
     17 int col[MAXN<<2];//lazy标记
     18 int n,m;
     19 void pushup(int l,int m,int r,int rt)
     20 {
     21         cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
     22         if (conl_1[rt<<1]==m-l+1)
     23         {
     24                 conl_1[rt]=conl_1[rt<<1]+conl_1[rt<<1|1];
     25         }        else conl_1[rt]=conl_1[rt<<1];
     26         if (conr_1[rt<<1|1]==r-m)
     27         {
     28                 conr_1[rt]=conr_1[rt<<1|1]+conr_1[rt<<1];
     29         }        else conr_1[rt]=conr_1[rt<<1|1];
     30         
     31         if (conl_0[rt<<1]==m-l+1)
     32         {
     33                 conl_0[rt]=conl_0[rt<<1]+conl_0[rt<<1|1];
     34         }        else conl_0[rt]=conl_0[rt<<1];
     35         if (conr_0[rt<<1|1]==r-m)
     36         {
     37                 conr_0[rt]=conr_0[rt<<1|1]+conr_0[rt<<1];
     38         }        else conr_0[rt]=conr_0[rt<<1|1];
     39         
     40         int tmx=conr_1[rt<<1]+conl_1[rt<<1|1];
     41         mx_1[rt]=max(tmx,max(mx_1[rt<<1],mx_1[rt<<1|1]));
     42         
     43         tmx=conr_0[rt<<1]+conl_0[rt<<1|1];
     44         mx_0[rt]=max(tmx,max(mx_0[rt<<1],mx_0[rt<<1|1]));
     45 }
     46 void build(int l,int r,int rt)
     47 {    
     48         col[rt]=-1;
     49         if (l==r)
     50         {
     51             scanf("%d",&col[rt]);
     52             if (col[rt]==1){
     53                 mx_0[rt]=0;
     54                 conl_0[rt]=conr_0[rt]=0;
     55                 mx_1[rt]=conl_1[rt]=conr_1[rt]=cnt[rt]=1;
     56             }
     57             else {
     58                 mx_0[rt]=1;
     59                 cnt[rt]=mx_1[rt]=0;
     60                 conl_0[rt]=conr_0[rt]=1;
     61                 conl_1[rt]=conr_1[rt]=0;
     62             }
     63             return;
     64         }
     65         int m=(l+r)>>1;
     66         build(lson);
     67         build(rson);
     68         pushup(l,m,r,rt);
     69 }
     70 void pushdown(int l,int m,int r,int rt)//还是lazy标志的改变是难点;
     71 {
     72         if (col[rt]!=-1)
     73         {
     74                 if (col[rt]==1)
     75                 {
     76                          col[rt<<1]=1;
     77                          conl_1[rt<<1]=conr_1[rt<<1]=mx_1[rt<<1]=m-l+1;
     78                          conl_0[rt<<1]=conr_0[rt<<1]=mx_0[rt<<1]=0;
     79                          cnt[rt<<1]=m-l+1;
     80                          
     81                          col[rt<<1|1]=1;
     82                               conl_1[rt<<1|1]=conr_1[rt<<1|1]=mx_1[rt<<1|1]=r-m;
     83                          conl_0[rt<<1|1]=conr_0[rt<<1|1]=mx_0[rt<<1|1]=0;
     84                          cnt[rt<<1|1]=r-m;
     85                 }else if (col[rt]==0)
     86                 {
     87                         col[rt<<1]=0;
     88                          conl_1[rt<<1]=conr_1[rt<<1]=mx_1[rt<<1]=0;
     89                         conl_0[rt<<1]=conr_0[rt<<1]=mx_0[rt<<1]=m-l+1;
     90                         cnt[rt<<1]=0;
     91                         
     92                         col[rt<<1|1]=0;
     93                         conl_1[rt<<1|1]=conr_1[rt<<1|1]=mx_1[rt<<1|1]=0;
     94                          conl_0[rt<<1|1]=conr_0[rt<<1|1]=mx_0[rt<<1|1]=r-m;
     95                          cnt[rt<<1|1]=0;
     96                 }else if (col[rt]==2)
     97                 {
     98                         
     99                     swap(conl_0[rt<<1],conl_1[rt<<1]);
    100                     swap(conr_0[rt<<1],conr_1[rt<<1]);
    101                     swap(mx_0[rt<<1],mx_1[rt<<1]);
    102                     cnt[rt<<1]=m-l+1-cnt[rt<<1];
    103                     
    104                     swap(conl_0[rt<<1|1],conl_1[rt<<1|1]);
    105                     swap(conr_0[rt<<1|1],conr_1[rt<<1|1]);
    106                     swap(mx_0[rt<<1|1],mx_1[rt<<1|1]);
    107                     cnt[rt<<1|1]=r-m-cnt[rt<<1|1];
    108                         
    109                      if (col[rt<<1]==0)//子段的标记不同,影响也不同
    110                      {
    111                          col[rt<<1]=1;    
    112                      }    else if (col[rt<<1]==1)
    113                      {
    114                          col[rt<<1]=0;
    115                      }    else if (col[rt<<1]==2)
    116                      {
    117                          col[rt<<1]=-1;
    118                      }    else if (col[rt<<1]==-1)
    119                      {
    120                             col[rt<<1]=2;
    121                      }
    122                      
    123                      if (col[rt<<1|1]==0)
    124                      {
    125                          col[rt<<1|1]=1;    
    126                      }    else if (col[rt<<1|1]==1)
    127                       {    
    128                          col[rt<<1|1]=0;
    129                      }    else if (col[rt<<1|1]==2)
    130                      {
    131                          col[rt<<1|1]=-1;
    132                      }    else if (col[rt<<1|1]==-1)
    133                      {
    134                             col[rt<<1|1]=2;
    135                      }    
    136                          
    137                 }
    138                 col[rt]=-1;    //清除lazy标志
    139         }
    140 }
    141 void update(int L,int R,int c,int l,int r,int rt)
    142 {
    143         if (L<=l && r<=R)
    144         {
    145                 if (c==2)
    146                 {
    147                     swap(conl_0[rt],conl_1[rt]);
    148                     swap(conr_0[rt],conr_1[rt]);
    149                     swap(mx_0[rt],mx_1[rt]);
    150                     cnt[rt]=r-l+1-cnt[rt];
    151                     //这里lazy标志的改变,错了好久,只能说lazy标识的不熟悉;
    152                     //lazy标记只对子段起作用,所以要更新当前段;
    153                     if (col[rt]==0)
    154                         {
    155                          col[rt]=1;//原先标记不同,标记更新也不同;    
    156                         }    else if (col[rt]==1)
    157                      {
    158                          col[rt]=0;
    159                      }    else if (col[rt]==2)
    160                      {
    161                          col[rt]=-1;
    162                      }    else if (col[rt]==-1)
    163                      {
    164                             col[rt]=2;
    165                      }
    166                 }else if (c==1)
    167                 {
    168                     conl_1[rt]=conr_1[rt]=mx_1[rt]=r-l+1;
    169                     conl_0[rt]=conr_0[rt]=mx_0[rt]=0;
    170                     cnt[rt]=r-l+1;
    171                     
    172                     col[rt]=1;//更新标记;
    173                 }if (c==0)
    174                 {
    175                     conl_1[rt]=conr_1[rt]=mx_1[rt]=0;
    176                     conl_0[rt]=conr_0[rt]=mx_0[rt]=r-l+1;
    177                     cnt[rt]=0;
    178                     
    179                     col[rt]=0;
    180                 }
    181                  
    182                 return;
    183         }
    184         int m=(l+r)>>1;
    185         pushdown(l,m,r,rt);
    186         if (L<=m) update(L,R,c,lson);
    187         if (m< R) update(L,R,c,rson);
    188         pushup(l,m,r,rt);
    189 }
    190 int query_num(int L,int R,int l,int r,int rt)//统计个数
    191 {
    192         if (L<=l && r<=R)
    193         {
    194             return cnt[rt];
    195         }        
    196         int m=(l+r)>>1;
    197         pushdown(l,m,r,rt);//每次询问都要先pushdown();
    198         int t1,t2;
    199         t1=t2=0;
    200         if (L<=m) t1=query_num(L,R,lson);
    201         if (m< R) t2=query_num(L,R,rson);
    202         return t1+t2;
    203 }
    204 int query_con(int L,int R,int l,int r,int rt)//统计连续1
    205 {
    206         if (L<=l && r<=R)
    207         {
    208                 return mx_1[rt];
    209         }
    210         int m=(l+r)>>1;
    211         pushdown(l,m,r,rt);
    212         int t1,t2;
    213         t1=t2=0;
    214         if (L<=m) t1=query_con(L,R,lson);
    215         if (m< R) t2=query_con(L,R,rson);
    216         int cl,cr,tmx=0;
    217         if (L<=m && m<R)
    218         {
    219             cl=min(conr_1[rt<<1],m-L+1);
    220             cr=min(conl_1[rt<<1|1],R-m);
    221             tmx=cl+cr;        
    222         } 
    223         return max(tmx,max(t1,t2));
    224 }
    225 int main()
    226 {
    227     int T;
    228     scanf("%d",&T);
    229     while (T--)
    230     {
    231             scanf("%d%d",&n,&m);
    232             build(1,n,1);
    233             while (m--)
    234             {
    235                 int a,b,c;
    236                 scanf("%d%d%d",&a,&b,&c);
    237                 b++;c++;
    238                 if (a==0)
    239                 {
    240                     update(b,c,a,1,n,1);    
    241                 }else if (a==1)
    242                 {
    243                     update(b,c,a,1,n,1);             
    244                 
    245                 }else if (a==2)
    246                 {
    247                     update(b,c,a,1,n,1);        
    248                 }else if (a==3)
    249                 {
    250                     int t=query_num(b,c,1,n,1);
    251                     printf("%d\n",t);
    252                 }else if (a==4)
    253                 {
    254                     int t=query_con(b,c,1,n,1);
    255                     printf("%d\n",t);
    256                 }
    257                 
    258             }
    259     }
    260     return 0;
    261 }
  • 相关阅读:
    C++内存泄露的有效预防方法:谁使用,谁删除 (1.2)
    工作日志2014-08-28
    【2012.1.24更新】不要再在网上搜索eclipse的汉化包了!
    关于ActionContext.getContext()的使用方法心得
    Android开发(20)--RadioGroup的使用
    站点防止攻击
    小强的HTML5移动开发之路(50)——jquerymobile页面初始化过程
    我是怎样成长为系统架构师的
    辛星站点架构师笔记第四篇
    strcpy_s与strcpy的比較
  • 原文地址:https://www.cnblogs.com/Rlemon/p/2683187.html
Copyright © 2011-2022 走看看