了解线段树(C++)

一.定义:
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
二.功能:
快速的查找某一个节点在若干条线段中出现的次数。(单点、区间的修改、查询)
三.时间复杂度:
O(logN)
四.注意:
实际应用时一般要开4N的数组以免越界。
未优化的空间复杂度为2N,有时需要离散化让空间压缩。
五.建树代码(以求区间和为例)
初步建树:

//p下标,l区间左界,r区间右界,mid线段中点
//a[i]输入的结点值,tree[i]区间和
void build(int p,int l,int r) 
{
    if(l==r)
   {
      tree[p]=a[l];
      return;
   }
  int mid=(l+r)/2;
  build(p*2,l,mid);
  build(p*2+1,mid+1,r);
  tree[p]=tree[p*2]+tree[p*2+1];
}

问题:当要对多个连续的结点(一个区间)进行加z操作时,如果直接将z加入到每个结点,将会使时间复杂度退化为O(N)。
所以增加了一个lazy数组,用lazy记录该区间要增加的数z,当该区间的下一个区间或者结点要被访问时,再将这个lazy记录的值传递下去。
加上lazy时的最终建树:

void build(int p,int l,int r)
{
 lazy[p]=0;
 if(l==r)
 {
     tree[p]=a[l];
     return;
 }
 int mid=(l+r)>>1;
 build(p*2,l,mid);
 build(p*2+1,mid+1,r);
 tree[p]=tree[p*2]+tree[p*2+1];
} 

对某个区间进行加/减运算:
(当z为正数时加,z为负数时减)

void add(int p,int l,int r,int x,int y,int z)
{
 if(x<=l&&r<=y)
 {
  lazy[p]+=z;
  tree[p]+=((long long)(r-l+1)) *z;
 }
 build(p,r-1+1);
 int mid=(l+r)>>1;
 if(x<=mid) add(p*2,l,mid,x,y,z);
 if(y>mid) add(p*2+1,mid+1,r,x,y,z);
 tree[p]=tree[p*2]+tree[p*2+1];
}

注:来源为百度和牛客算法竞赛入门班笔记。
此外如有错误,欢迎指出。

猜你喜欢

转载自blog.csdn.net/weixin_47534339/article/details/107599848