ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树状数组 线段树 后缀数组

2022-05-21 18:01:36  阅读:108  来源: 互联网

标签:func val 树状 后缀 sum nums int add 数组


最近学习到新东西,有点意思
线段树

树状数组

范围内改单点求区间和

307 区域和检索
  • 树状数组
var n int
var tree []int

func lowBit(x int)int{
    return x&(-x)
}

//更新向上
func update(pos int, val int){
    pos++
    for pos<=n{
        tree[pos]+=val
        pos+=lowBit(pos)
    }
}

func query(pos int)int{
    res:=0
    for pos>0{
        res+=tree[pos]
        pos-=lowBit(pos)
    }
    return res
}

type NumArray struct {
   arr []int
}


func Constructor(nums []int) NumArray {
    var num NumArray
    n = len(nums) //从1开始
    tree = make([]int,n+1) 
    for i:=0;i<len(nums);i++{
        update(i,nums[i])
    }
    num.arr = make([]int,n)
    copy(num.arr,nums)
    return num
}


func (this *NumArray) Update(index int, val int)  {
    update(index,val-this.arr[index])
    this.arr[index] = val
}


func (this *NumArray) SumRange(left int, right int) int {
    return query(right+1)-query(left)    //整体加1
}

线段树

范围内数据求和或者最大值(O(logn)更新和查询)
有点和树状数组类似

  • 包含延迟标记
package main

import (
	"fmt"
)

//区间修改,区间查询,延迟标记

type Tree struct {
	l,r int  //左右索引
	sum int  //区间和
	add int  //延迟标记
}

var t []Tree  //线段树变量
var nums []int //具体数组的值,由此数组构成线段树

//构建线段树
func build(p,l,r int){  //l r 为数组左右边界下标,从1开始
	t[p].l,t[p].r= l,r
	if l==r{
		t[p].sum = nums[l]  //具体和需要数组
		return
	}
	mid:=(l+r)/2
	build(p*2,l,mid)
	build(p*2+1,mid+1,r) //右边子树
	t[p].sum = t[p*2].sum+t[p*2+1].sum //子树之和
}

func spread(p int){ //延迟修改标记   先更新左右节点信息,再打标记    带标记说明此层已经修改,下一层未修改
	if t[p].add>0{
		t[p*2].sum+=t[p].add*(t[p*2].r-t[p*2+1].l+1) //更左边子树区间和
		t[p*2+1].sum +=t[p].add*(t[p*2+1].r-t[p*2+1].l+1) //更右边
		t[p*2].add+=t[p].add  //左边标记
		t[p*2+1].add +=t[p].add
		t[p].add=0  //清除标记
	}
}

//区间修改,l到r 增加d,(如果修改单点,需要注意是增两者差值)
func update(p,l,r,d int){
	if l<=t[p].l&&r>=t[p].r{
		t[p].sum+=d*(t[p].r-t[p].l+1)
		t[p].add+=d
		return
	}
	// 执行延迟下标
	spread(p)
	mid:=(t[p].l+t[p].r)/2
	if l<=mid{
		update(p*2,l,r,d)
	}
	if r>mid{
		update(p*2+1,l,r,d)
	}
	//返回上层更新区间和,是重新计算
	t[p].sum = t[p*2].sum+t[p*2+1].sum
}

//区间查询
func ask(p,l,r int)int{
	if l<=t[p].l&&r>=t[p].r{
		return t[p].sum
	}
	spread(p) //执行延迟下标
	mid:=(t[p].l+t[p].r)/2
	val:=0
	if l<=mid{
		val+=ask(p*2,l,r)
	}
	if r>mid{
		val+=ask(p*2+1,l,r)
	}
	return val
}

//********************************************************************** 线段树 区间查询 已通过leetcode 307测试

//更改单点值
func updatePoint(index,val int){
	update(1,index+1,index+1,val-nums[index+1])
	nums[index+1] = val
}

func main(){
	nums = []int{0,1,2,3,4}  //0位置不使用,默认从1开始
	t=make([]Tree,4*len(nums))   //开四倍空间足够使用
 	build(1,1,4)
	fmt.Println(ask(1,1,4))  //1-4区间和

	updatePoint(0,2)  //下标1位置数据改为2

	fmt.Println(ask(1,1,4))  //1-4区间和
}

后缀数组

处理字符串所有后缀,最长公共前缀 (待更新)

标签:func,val,树状,后缀,sum,nums,int,add,数组
来源: https://www.cnblogs.com/9527s/p/15202997.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有