线段树
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 );
}
}
}
以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章