线段树简述

线段树是一棵二叉搜索树,常用于解决区间问题。

线段树每一个非叶子节点[left,right],它的左二子区间[left,(left+right)/2],右儿子区间[(left+right)/2+1,right]。

线段树的结构体,内元素包括,此节点包含区间[left,right],和value

    //线段树结构体  
    #include <bits/stdc++.h>  
    using namespace std;  
    const int maxn = 1<<20;  
    const int N;  
    struct Node {  
        int value;   //检点区间权值  
        int left, right;  //区间(left,right)  
    }node[maxn];  
    int father[N];  //每个点(当区间长度为0时,对应的结构体数组下标)  

线段树的建立

    void BuildTree(int i, int left, int right)  
    {  
        node[i].left = left;  //写入第i个结点的左区间  
        node[i].right = right;  //写入第i个结点的右区间  
        node[i].value = 0;  //区间权值初始化为0  
        if(left == right) {  
            father[left] = i;  //知道每个点对应的序号(结点的下标)  
            return;  
        }  
        //建立左子树  
        BuildTree(i<<1, left, (left+right)/2);  
        //建立右子树  
        BuildTree((i<<1)+1, (left+right)/2+1, right);  
    }  

单点更新线段树

因为事先用father[]数组保存过每个节点对应的的下标,因此只要知道第几个点,就知道这个点在树中的位置(即下标),这样就只要一路向上更新上去即可。


    void UpdateTree(int r1)  
    {  
        if(r1 == 1) return;   //已找到祖先  
        int fi = r1/2;          //ri的父节点  
        int a = node[fi<<1].value;   //该父节点的两个孩子  
        int b = node[(fi<<1)+1].value;  //右  
        node[fi].value = (a > b) ? a : b;  
        UpdateTree(ri/2);  //递归更新,有父节点往上找  
    }  

查询区间最大值

讲一段区间从上往下拆开,直到存在有完全重合的区间停止。

    int Max = -1<<20;  
    void Query(int i, int l, int r)  
    {  
        if(node[i].left == l && node[i].right == r) {  
            Max = (Max < node[i].value) ? (node[i].value) : (Max);  
            return;  
        }  
        i = i << 1;  
        if(l <= node[i].right) {    //左区间有涉及  
            if(r <= node[i].right)   //全包含于左区间,则查询形态不变  
                Query(i, l, r);  
            else          //半包含于左区间,则查询区间拆分,左端点不变,右端点变为左区间的右孩子端点  
                Query(i, l, node[i].right);  
        }  
        i += 1;  
        if(r >= node[i].left) {    //右区间有涉及  
            if(l >= node[i].left)  //全包含于右区间,则查询形态不变  
                Query(i, l, r);  
            else        //半包含于右区间,则查询区间拆分  
                Query(i, node[i].left, r);  
        }  
    }  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值