线段树专题

线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段/一段区间(数组中的一段子数组),主要用于解决连续区间的动态查询问题。

关于线段树的建立(以 1 2 3 4 5为例)

这里写图片描述

我们把1~5这5个数,分为2个区间(1,3)和(4,5),之后判断区间是否可以继续再分,(1,3)明显可以分为(1,2)和(3,3)/3 ,把(1,2)继续向下分,3不用继续分,就把a[3]存入b数组之中,此时3位于这个数的第3层(设根节点所在的层为第1层),即b[2*2+1]=b[5]=a[3] ;

同理:
b[5]=a[3]; (2*2+1)
b[6]=a[4];
b[7]=a[5];
b[8]=a[1]; (2*2*2)
b[9]=a[2];
b[1],b[2],b[3],b[4]为根节点,他们的值为节点中较大的那个值;即
b[4]=max( b[8], b[9] );
b[3]=max( b[6], b[7] );
b[2]=max( b[4], b[5] );
b[1]=max( b[2], b[3] );
// 大致的 b[n]=max( b[2^(n+1)+1] , b[2^(n+1)+2] ); (n为2的倍数)

建立线段树的代码(利用二分思想):

void build(int i,int l,int r) // i:深度   l:左    r:右 
{
    if(l==r)
        b[i]=a[l];
    else
    {
        build(2*i,l,(l+r)/2);
        build(2*i+1,(l+r)/2+1,r);
        b[i]=max(b[2*i],b[2*i+1]);
    }
}

更新代码(需要把A改成B): //更新的是节点

1),如果更新的是某个区间,则利用2分的思想,把需要查找的区间分成小的区间,直到不能继续向下进行;
2),当需要更新的区间是某个节点,即(3,3),只需要更新一个节点
3),我们进行更新操作的时候,只需要更新b[i]位置的数据。
4),

void updata(int i,int l,int r) // 1 1 n  A--B  1 1 5    // eg: a[]={1 2 3 4 5} ,更新 2 3   
{
    if(l==r)
        b[i]=B;  b[8]=B;
    else
    {
        int mid=(l+r)/2; 3
        if(A<=mid)
            updata(2*i,l,(l+r)/2);2 1 3 == 4 1 2 == 8 1 1 
           //这里就开始递归调用
        else
            updata(2*i+1,(l+r)/2+1,r);
           //这里就开始递归调用

        b[i]=max(b[2*i],b[2*i+1]);
        //在上面的递归过程中,已经更新到b[i],下面的过程即回溯,更新b[i]相关的节点。
    }
}

1),如果查找的区间超出我们的区间,则返回-1
2),如果查找的区间在二叉树的某一侧,只需要返回b[k]位置的数据
3),如果查找的区间在二叉树的两侧,我们需要把区间分开查询,较大的数据,为父节点(向下分的时候为一个区间)或者节点(向下无法继续,为一个节点)

查找代码(需要查找的区间为(A,B)): //查找的是区间

int query(int k,int begin,int end)
{
    int p1,p2;
    if(A>end||B<begin)
        return -1;
    if(begin>=A&&end<=B)
        return b[k];
    p1=query(2*k,begin,(begin+end)/2);
    p2=query(2*k+1,(begin+end)/2+1,end);
    return max(p1,p2);
}

应用:
杭电1754:
http://acm.hdu.edu.cn/showproblem.php?pid=1754

hdu 1754详解:
http://blog.csdn.net/acm_hmj/article/details/53292137

相关解决区间问题的树状数组:
http://blog.csdn.net/acm_hmj/article/category/6528247

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值