码迷,mamicode.com
首页 > 其他好文 > 详细

线段树1

时间:2018-01-06 18:00:32      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:链表   cpp   down   结构体   careful   思路   else   自己   递归   

线段树的基本操作
1、特点:与普通的树不同,线段树存取的是某一个区间,它在各个节点保存一条线段。
2、节点储存方式:(结构体)
方式一:数组储存

struct Tree
{
        int leftnode, rightnode; //区间的最左端和最右端
        long long sum;           //该节点储存区间的值
} tree[N *4];          //比常规储存的数组要大四倍(Be careful!)

方式二:链表储存(自己了解)

struct Tree
{
     int Left, Right;
     Tree  *Leftchild , *Rightchild;
 }

3、建树
思路: if(叶节点) 存值,返回;
else 递归,查找左右孩子;
最后一定要记得回溯,维护区间;

void  Build_Tree ( int left , int right , int i )
{
    tree[i].leftnode = left;
tree[i].rightnode = right;     //存储区间最左端、最右端
if( left == right )
tree[i].sum = a[x] ;        //叶子节点,存值
    else
    {
        int  mid = (tree[i].leftnode+ tree[i].rightnode)/2;
 //↑↑↑可以尝试用位运算代替,速度会加快
        Build_Tree (   left  ,  mid  , i/2  );  //遍历左子树
        Build_Tree ( mid + 1 , right , i/2+1); //遍历右子树
        tree[i].sum = ……;(回溯,对线段树进行维护)
    }
}

4、查找线段树上的位置
思路: 递归查询
If(被左儿子覆盖)
查询左儿子;
Else if(被右儿子覆盖)
查询右儿子;
Else //即左右儿子都有
都查询;

int Query_Tree ( int left , int  right , int  i ) //Query:查找、查询
{    //left,right:查找目标的区间
if ( left<= tree[i].leftnode && right >= tree[i].rightnode )  
return tree[i].sum;  //当前结点的区间完全被目标区间覆盖
    else
    {
        int mid = (tree[i].leftnode+ tree[i].rightnode)/2;
        if( left > mid )       //目标区间被左儿子覆盖
            return Query_Tree ( left , right , i/2+1);
        else if (rifgt<= mid ) //目标区间被右儿子覆盖
            return Query_Tree ( left , right , i/2 );
        else                    //目标区间在左右都有分部
    return Query_Tree ( left , right , i/2) + Query_Tree ( left , right , i/2+1 );
    }
}

5、树节点值的更新与维护
思路 更新很容易,查询到位置后替换即可,重要的是维护,回溯即可
If(目标子节点)
更新;
Else
{
If(被左儿子覆盖)
查询左儿子;
If(被右儿子覆盖)
查询右儿子;
}
回溯,更新父节点值;

void  Update_Tree ( int aimnode  , int i ) //update更新 aimnode目标子节点
{
if(tree[i].leftnode == aimnode && tree[i].rightnode == aimnode)
 //找到需要修改的叶子节点
    {
          tree[i].sum = ㊣ ; //更新当前结点 ,㊣为要更新的值
    }
    else       //当前结点是非叶子结点
    {
        int mid = (tree[i].leftnode+ tree[i].rightnode )/2 ; 
        if ( aimnode <= mid ) //目标节点在左儿子中
        {
             Update_Tree ( aimnode , i/2 );
        }
        else if( aimnode > mid ) //目标节点在右儿子中
        {
            Update_Tree ( aimnode , i/2+1 );
        }
        tree[i].sum = tree[i/2].sum + tree[i/2+1].sum; //回溯
    }
}

【练习】
http://codevs.cn/problem/1228/ 苹果树
http://codevs.cn/problem/1080/ 线段树练习
http://codevs.cn/problem/1217/ 借教室
https://www.luogu.org/problem/show?pid=3372 【模板】线段树 1

线段树1

标签:链表   cpp   down   结构体   careful   思路   else   自己   递归   

原文地址:https://www.cnblogs.com/tply/p/8214727.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!