线段树

   如果给出了一个数组,a[1]~a[N],要你求出它在[l.r]区间的和,同时还要你修改某一个的值时,如果用暴力求解,有时候数据会爆掉,时间复杂度为O(n*n),也无法通过,这时候线段树就派上用场了。

     线段树实际上就是一个二叉树,同时它的每个节点上又存有一定的信息。使用线段树,它每完成一次的时间复杂度为O(log2N)。如果要求的区间为[l,r],那么对于任何一个非子叶的节点,它的左儿子为[l,(l+r)/2],右儿子为[((l+r)/2)+1,r]。

    每一个节点,由于它要记录信息,先建一个结构体,具体如下:

struct Node
{
    int L,R;
    int sum;
}Node[Max<<2];

    后面,我们需要建立一个线段树,在这个过程中采用递归的思想。代码如下:

void build(int i, int l, int r)
{
    Node[i].L = l;
    Node[i].R = r;
    Node[i].sum=0;
    if(l == r)
    {
        Node[i].sum=a[l];
        return;
    }
    int mid = (l + r)>>1;        //相当于(l+r)/2
    build(i<<1, l, mid);            //相当于i*2
    build((i<<1)|1, mid + 1, r);       //相当于i*2+1
    pushUp(i);
}

      代码里面,有一个pushUp()函数,这是一个不断更新节点的值的函数,一个节点的值为它的两个分支的和,故代码:

void pushUp(int i)
{
    int lson = i<<1;
    int rson = lson + 1;
    Node[i].sum = Node[lson].sum+Node[rson].sum;
}

   题目往往会要求我们更改某一个位置的值,这时就需要一个Update()函数,这个函数仍然使用递归的思想

void update(int i,int loc,int value)
{
    if(Node[i].L == Node[i].R)
    {
        Node[i].sum =value;
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(loc <= mid) update(i<<1, loc, value);
    else update((i<<1)|1, loc, value);
    pushUp(i);
}

同时,我们要满足线段树的查询功能,即可以知道[l,r]区间的sum和,代码如下:

int query(int i, int l, int r)
{

    if(Node[i].L == l && Node[i].R == r)
    {
        return Node[i].sum;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid) return query(i<<1, l, r);
    else if(l > mid) return query((i<<1)|1, l, r);
    else
    {
        return query(i<<1, l, mid) + query((i<<1)|1, mid + 1, r);
    }
}

线段树的代码就大致如上,几乎所有都可以用此模板来写。不同的线段数只是维护的对象不一样,有的维护sum,有的维护max,min,这要依题目而定。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值