线段树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。

线段树:

这个星期是线段树的专题,真心觉得线段树难,但是还是要硬着头皮看!线段树是将区间逐渐二分得到的一种树状结构,运用了包括归并排序内的很多算法!

线段树的基本操作:

1.定义

2.建树

3.点修改

4.区间求和

 

1.定义:

struct Tree
{

int l, r;
long long sum;

} tr[maxN << 2];

  

2.建树:

void Build_Tree ( int x , int y , int i )
{

   tr[i].l = x;
   tr[i].r = y;

   if( x == y )

        tr[i].sum = a[x] ; //找到叶子节点,赋值

   else
      {
         ll mid = (tr[i].l tr[i].r ) >> 1 ;

         Build_Tree ( x , mid , i << 1); //左子树

         Build_Tree ( mid + 1 , y , i << 1 | 1); //右子树

         tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum; //回溯维护区间和

      }
}

 

3.点修改

void Update_Tree ( int q , int val , int i )
{
         if(tr[i].l == q && tr[i].r == q) //找到需要修改的叶子节点
             tr[i].sum = val ; //更新当前结点
         else //当前结点是非叶子结点
          {
               long long mid = (tr[i].l tr[i].r ) >> 1 ; //取中间

               if ( q <= mid ) //目标节点在左儿子中
                   Update_Tree ( q , val , i << 1 );
               else if( q > mid ) //目标节点在右儿子中
                   Update_Tree ( q , val , i << 1 | 1 );
              tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum; //回溯
          }
}

 

4.区间求和

long long Query_Tree ( int q , int w , int i )
{
    if ( q <= tr[i].l && w >= tr[i].r ) return tr[i].sum; //当前结点的区间完全被目标区间包含
    else
    {
        long long mid = (tr[i].l tr[i].r) >> 1;
        if( q > mid ) //完全在左儿子
        {
            return Query_Tree ( q , w , i << 1 | 1);
        }
        else if (w <= mid ) //完全在右儿子
        {
            return Query_Tree ( q , w , i << 1);
        }
        else //目标区间在左右都有分布
        {
            return Query_Tree ( q , w , i << 1) + Query_Tree ( q , w , i << 1 | 1 );
        }
    }
}

 

 

 

 

 

 

以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

线段树合并

数据结构——线段树

论线段树:二

线段树