线段树

概念:

线段树:线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。

线段树是善于处理区间问题的。线段树是一棵完美的二叉树(所有的叶子的深度都一样,并且每个节点要么是叶子要么有两个儿子的树),树上的每一个节点都维护一个区间。根维护的是整个区间,每一个节点维护的是父亲的区间二等分后的其中的一个子区间。当有n个元素时,对区间的操作可以在O(log n)的时间内完成。

                                    

根据节点中维护的数据的不同,线段树可以提供不同的操作。下面实现了Range Minimum Query(RMQ)操作的线段树为例,进行说明。

基于线段树的RMQ的结构

一. 基于线段树的MRQ的查询:

查询一个较大的区间,由于靠上的节点对应较大的区间,通过这些区间就可以知道大部分的值的最小值,从而只需要访问很少的节点就可以求出最小值。

(1)如果要查询的区间和当前的节点对应的区间完全没有交集,那么久返回一个不影响结果的值INT_MAX;

(2)如果所查询的区间完全包含了当前结点对应的区间,那么就直接返回当前结点的值;

(3)以上两种情况都不满足的话,那么就对两个儿子递归处理,返回两个结果中的最小值;

int query(int a,int b,int k,int l,int r)//查询最小值;
{
    if(r<=a||b<=l)//不包含在这个区间内;
        return INT_MAX;
    if(a<=l&&r<=b)//完全包含在这个区间内;
        return dat[k];
    else
    {
        int v1=query(a,b,k*2+1,l,(l+r)/2);
        int v2=query(a,b,k*2+2,(l+r)/2,r);
        return min(v1,v2);//两个值取最小的值;
    }
}

二 .基于线段树的RMQ的值的更新:

在更新值后,对于线段树要进行全局的维护:从下向上进行值的更新,更新为两个子节点中的最小值就可以了。


void update(int k,int a)//更新值为a;
{
    k+=n-1;
    dat[k]=a;
    while(k>0)
    {
        k=(k-1)/2;
        dat[k]=min(dat[k*2+1,dat[k*2+2]);//上面的依次更新;
    }
}

代码演示:

#include<set>
#include<map>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int N=1<<17;
const int INT_MAX=99999999;

int n;
int dat[N*2-1];//存储线段树的数组;

void init(int n_)//初始化;
{
    n=1;
    while(n<n_)
        n*=2;
    for(int i=0; i<2*n-1; i++)
    {
        dat[i]=INT_MAX;
    }
}

void update(int k,int a)//更新值为a;
{
    k+=n-1;
    dat[k]=a;
    while(k>0)
    {
        k=(k-1)/2;
        dat[k]=min(dat[k*2+1,dat[k*2+2]);//上面的依次更新;
    }
}

int query(int a,int b,int k,int l,int r)//查询最小值;
{
    if(r<=a||b<=l)//不包含在这个区间内;
        return INT_MAX;
    if(a<=l&&r<=b)//完全包含在这个区间内;
        return dat[k];
    else
    {
        int v1=query(a,b,k*2+1,l,(l+r)/2);
        int v2=query(a,b,k*2+2,(l+r)/2,r);
        return min(v1,v2);//两个值取最小的值;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值