zoukankan      html  css  js  c++  java
  • 线段树学习(segment tree)

    今天在B站学习了线段树,up主讲得很清晰。

    引入:我们在一个数组中如果想更新一个数据的值,记为update,所用的时间复杂度是o(1),而求某一段区间的端点值之和,记为query,时间复杂度是o(n)。

    求某一段区间的长度之和可以采用端点前缀和相减,建立一个前缀和数组,[l,r]的值等于sum[r]-sum[l-1],这样把时间复杂度降到了o(1),可是update时间复杂度就退化为o(n)。

    因为每次更新一个数据,就需要维护所有的前缀和。

    由此我们引入了线段树,线段树可以实现update和query时间复杂度为o(logn)。

    步骤主要有:建树、单点更新、区间查询。

    首先是建树,把区间进行分隔。

     

    void build_node(int arr[],int tree[],int node,int start,int end)
    {
        if(start==end){//递归出口
            tree[node]=arr[start];
            return;
        }
        int mid=(start+end)/2;
        int left_node=2*node+1;//左儿子对应的数组编号
        int right_node=2*node+2;//右儿子对应的数组编号
    build_node(arr,tree,left_node,start,mid);//递归左子树,区间为[start,mid] build_node(arr,tree,right_node,mid
    +1,end);//递归右子树,区间为[mid+1,end] tree[node]=tree[left_node]+tree[right_node];//结点值等于左右儿子相加 }

    接下来是实现单点更新update的代码,将arr[4]更新为6。

     

    void update_tree(int arr[],int tree[],int node,int start,int end,int idx,int val)
    {
        if(start==end){
            arr[idx]=val;
            tree[node]=val;
            return ;
        }
        int mid=(start+end)/2;
        int left_node=2*node+1;
        int right_node=2*node+2;
        if(idx>=start&&idx<=mid){//如果在左分支里面
            update_tree(arr,tree,left_node,start,mid,idx,val);
        }
        else {//否则在右分支
            update_tree(arr,tree,right_node,mid+1,end,idx,val);
        }
        tree[node]=tree[left_node]+tree[right_node];
    }

    实现区间查询query的代码

    int query_tree(int arr[],int tree[],int node,int start,int end,int L,int R)
    {
        ///printf("%d %d
    ", start, end);
        if(start>R||end<L)return 0;
        if(start==end||start>=L&&end<=R){
            return tree[node];
        }
        int mid=(start+end)/2;
        int left_node=node*2+1;
        int right_node=node*2+2;
        int sum_left=query_tree(arr,tree,left_node,start,mid,L,R);
        int sum_right=query_tree(arr,tree,right_node,mid+1,end,L,R);
        int sum=sum_left+sum_right;
        return sum;
    }

    源代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define MAX_LEN 1000
    void build_node(int arr[],int tree[],int node,int start,int end)
    {
        if(start==end){
            tree[node]=arr[start];
            return;
        }
        int mid=(start+end)/2;
        int left_node=2*node+1;
        int right_node=2*node+2;
        build_node(arr,tree,left_node,start,mid);
        build_node(arr,tree,right_node,mid+1,end);
        tree[node]=tree[left_node]+tree[right_node];
    }
    void update_tree(int arr[],int tree[],int node,int start,int end,int idx,int val)
    {
        if(start==end){
            arr[idx]=val;
            tree[node]=val;
            return ;
        }
        int mid=(start+end)/2;
        int left_node=2*node+1;
        int right_node=2*node+2;
        if(idx>=start&&idx<=mid){
            update_tree(arr,tree,left_node,start,mid,idx,val);
        }
        else {
            update_tree(arr,tree,right_node,mid+1,end,idx,val);
        }
        tree[node]=tree[left_node]+tree[right_node];
    }
    int query_tree(int arr[],int tree[],int node,int start,int end,int L,int R)
    {
        printf("%d %d
    ", start, end);
        if(start>R||end<L)return 0;
        if(start==end||start>=L&&end<=R){
            return tree[node];
        }
        int mid=(start+end)/2;
        int left_node=node*2+1;
        int right_node=node*2+2;
        int sum_left=query_tree(arr,tree,left_node,start,mid,L,R);
        int sum_right=query_tree(arr,tree,right_node,mid+1,end,L,R);
        int sum=sum_left+sum_right;
        return sum;
    }
    int main()
    {
        int arr[]={1,3,5,7,9,11};
        int tree[MAX_LEN]={0};
        int size=6;
        build_node(arr,tree,0,0,size-1);
        for(int i=0;i<15;i++){
            printf("tree[%d] = %d
    ",i,tree[i]);
        }
        printf("
    ");
        /*update_tree(arr,tree,0,0,size-1,4,6);
        for(int i=0;i<15;i++){
            printf("tree[%d] = %d
    ",i,tree[i]);
        }*/
        cout<<query_tree(arr,tree,0,0,size-1,4,5)<<endl;
        return 0;
    }
    View Code

     

  • 相关阅读:
    第一章计算机系统知识
    Java面试宝典摘抄
    Java的容器类Collection和Map
    log4j.properties 详解与配置步骤(转)
    JSTL中的TLD配置和使用。
    (原创)mybatis学习四,利用mybatis自动创建代码
    C#常用方法
    Spring 3.x jar 包详解 与 依赖关系
    spring mvc JSON实现方式
    Structs2配置文件相关说明
  • 原文地址:https://www.cnblogs.com/mohari/p/12873086.html
Copyright © 2011-2022 走看看