• 树状数组 线段树 后缀数组


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

    树状数组

    范围内改单点求区间和

    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区间和
    }
    

    后缀数组

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

  • 相关阅读:
    编译原理学习导论-作者四川大学唐良(转)初学者必看
    Ajax在chrome浏览器中测试调用失败解决办法
    sublime中输入法输入框只能在一个位置
    第三次作业
    第二次作业
    第一次作业
    2018年 大一下学期第零次作业
    14,15周作业
    第七周作业
    第六周作业
  • 原文地址:https://www.cnblogs.com/9527s/p/15202997.html
Copyright © 2020-2023  润新知