[go刷题模板] 树状数组

一、 算法&数据结构

1. 描述

PURQ的树状数组可以用来单点更新区间查询
  • 模板慢慢补充,更详细的可以看我的py版本。

2. 复杂度分析

  1. 查询query, O(log2n)
  2. 更新update,O(log2n)

3. 常见应用

4. 常用优化

二、 模板代码

1. 单点更新,区间询问求和(PURQ)

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
	"sort"
)

// BIT 420 ms
func solve(in io.Reader, out io.Writer) {
	var n int
	Fscan(in, &n)
	type seg struct{ i, l, r int }
	var hs []int
	a := make([]seg, n)
	for i := 0; i < n; i++ {
		Fscan(in, &a[i].l, &a[i].r)
		hs = append(hs, []int{a[i].l, a[i].r}...)
		a[i].i = i
	}
	sort.Slice(a, func(i, j int) bool { return a[i].r < a[j].r })
	sort.Ints(hs)
	ans := make([]int, n)
	p := NewBIT(n * 2)
	for _, s := range a {
		l, i := s.l, s.i
		l = sort.Search(len(hs), func(i int) bool { return hs[i] >= l })
		ans[i] = p.SumInterval(l+1, n*2+1)
		p.AddPoint(l+1, 1)
	}

	for _, v := range ans {
		Fprintln(out, v)
	}
}
func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	solve(in, out)
}

func main() { run(os.Stdin, os.Stdout) }


type BIT struct {
	C []int
	N int
}

func NewBIT(n int) BIT {
	c := make([]int, n+2)
	return BIT{c, n}
}

// AddPoint
// 给i位置增加v,注意i是1-indexed
func (u *BIT) AddPoint(i, v int) {
	for i <= u.N {
		u.C[i] += v
		i += i & -i
	}
}

// SumPrefix
// 计算[..i]的前缀和,包含i,注意i是1-indexed
func (u BIT) SumPrefix(i int) int {
	s := 0
	for i >= 1 {
		s += u.C[i]
		i &= i - 1
	}
	return s
}

// SumInterval SumIn
// 计算[l..r]闭区间的和,注意l\r是1-indexed
func (u BIT) SumInterval(l, r int) int {
	return u.SumPrefix(r) - u.SumPrefix(l-1)
}

// Lowbit
// 计算lowbit,L
func (u BIT) Lowbit(x int) int {
	return x & -x
}

// MinRight 查找[i..]后第一个>=0的位置,包含i,注意i是1-indexed
func (u BIT) MinRight(i int) int {
	p := u.SumPrefix(i)
	if i == 1 {
		if p > 0 {
			return i
		}
	} else {
		if p > u.SumPrefix(i-1) {
			return i
		}
	}
	l, r := i, u.N+1
	for l+1 < r {
		mid := (l + r) >> 1
		if u.SumPrefix(mid) > p {
			r = mid
		} else {
			l = mid
		}
	}
	return r
}

三、其他

四、更多例题

五、参考链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值