在写这篇博客之前首先申明一下,这个线段树的名字是我的好队友 shu_mj 取的。由于实在很好用,对于新手容易上手所以写一篇博客造福老百姓。

然后说明一下这仅仅是一篇关于线段树入门的文章。

单点更新:

单点更新不需要标记整个线段树只需要自底向上的维护值(最小值,最大值,和等)就行了。实现难度较低,新手也能很快学会。

在线段树中每个节点的含义都是一个线段根节点表示的是1-n的线段,假设根节点标号是o,他的左子树标号为o<<1,右子树标号为o<<1|1相应的左子树表示的区间为1-m(m=(l+r)>>1),而右子树表示的区间为m+1-r

这样我们用一颗高度为logn 的树即可表示整条线段了。

对于单点更新的线段树每个标记都能下放到最底层,由于每次下放标记最多沿着一路走所以每次操作的复杂度为logn的。

对于求和的时候我们把区间不断的拆分用线段树上的小区间(节点表示的区间)来拼成需要求和的完整区间,最后将这些节点上的标记累加起来即为答案。复杂度同样为logn的。

代码如下:

 1 int num[LEN], sum[4*LEN], n;
 2 
 3 void pushup(int o){
 4     sum[o] = sum[o<<1] + sum[o<<1|1];
 5 }
 6 
 7 void build(int l, int r, int o){
 8     if(l == r){
 9         //设初值
10         return ;
11     }
12     int m = (l + r)/2;
13     build(l, m, o<<1);
14     build(m+1, r, o<<1|1);
15     pushup(o);
16 }
17 
18 void update(int l, int r, int o, int pos, int val){
19     if(l == r) {
20         sum[o] += val;
21         return ;
22     }
23     int m = (l + r)/2;
24     if(pos <= m) update(l, m, o<<1, pos, val);
25     else update(m+1, r, o<<1|1, pos, val);
26     pushup(o);
27 }
28 
29 int query(int l, int r, int o, int L, int R){
30     if(l >= L && r <= R) return sum[o];
31     int m = (l + r) / 2, ret = 0;
32     if(L <= m) ret += query(l, m, o<<1, L, R);
33     if(R > m) ret += query(m+1, r, o<<1|1, L, R);
34     return ret;
35 }
View Code

相关文章:

  • 2022-12-23
  • 2021-07-25
  • 2022-12-23
  • 2022-12-23
  • 2021-09-30
  • 2021-09-08
猜你喜欢
  • 2021-07-14
  • 2021-05-19
相关资源
相似解决方案