线段树小结

 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 }

 

你可能感兴趣的:(线段树)