线段树小结

 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 }
原文地址:https://www.cnblogs.com/Rlemon/p/2683187.html