結果
問題 |
No.1435 Mmm......
|
ユーザー |
|
提出日時 | 2025-02-25 16:15:28 |
言語 | Go (1.23.4) |
結果 |
AC
|
実行時間 | 199 ms / 2,000 ms |
コード長 | 11,761 bytes |
コンパイル時間 | 18,659 ms |
コンパイル使用メモリ | 249,576 KB |
実行使用メモリ | 12,076 KB |
最終ジャッジ日時 | 2025-02-25 16:15:53 |
合計ジャッジ時間 | 24,026 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 24 |
ソースコード
// 线段树的空间优化版本,支持区间查询、单点修改: // // - NewRadixTree(e, op, log): 构造一个新的线段树,e 是幺元,op 是结合律,log 是每个块的大小。 // - Build(n, f): 构建长度为 n 的线段树,f 是初始化函数。 // - QueryRange(l, r): 查询 [l,r) 区间的聚合值。 // - QueryAll(): 查询所有元素的聚合值。 // - Get(i): 查询第 i 个元素的值。 // - GetAll(): 查询所有元素的值。 // - Update(i, v): 将第 i 个元素更新为 v。 // - Set(i, v): 将第 i 个元素设置为 v。 package main import ( "bufio" "fmt" "math/rand" "os" "slices" "time" ) func main() { // testTime() // for i := 0; i < 1000; i++ { // test() // } // fmt.Println("pass") yuki1435() } func yuki1435() { in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var n int fmt.Fscan(in, &n) nums := make([]int, n) for i := 0; i < n; i++ { fmt.Fscan(in, &nums[i]) } const INF int = 1e18 type E = struct{ max1, min1, min2 int } // max/min1/min2 e := func() E { return E{-INF, -INF, -INF} } op := func(a, b E) E { aMax1, aMin1, aMin2 := a.max1, a.min1, a.min2 bMax1, bMin1, bMin2 := b.max1, b.min1, b.min2 if aMax1 == -INF { return b } if bMax1 == -INF { return a } if aMin1 < bMin1 { return E{max(aMax1, bMax1), aMin1, min(aMin2, bMin1)} } return E{max(aMax1, bMax1), bMin1, min(bMin2, aMin1)} } seg := NewRadixTree(e, op, -1) seg.Build(n, func(i int) E { return E{nums[i], nums[i], INF} }) res := 0 for left := 0; left < n; left++ { right := seg.MaxRight(left, func(e E) bool { return e.max1 <= e.min1+e.min2 }) res += right - left - 1 } fmt.Fprintln(out, res) } // 2213. 由单个字符重复的最长子字符串 // https://leetcode.cn/problems/longest-substring-of-one-repeating-character/ // ![l,r]区间的最大连续长度就是 // !左区间的最大连续长度,右区间最大连续长度,以及左右两区间结合在一起中间的最大连续长度. func longestRepeating(s string, queryCharacters string, queryIndices []int) []int { type E = struct { size int preMax, sufMax, max int // 前缀最大值,后缀最大值,区间最大值 lc, rc byte // 区间左端点字符,右端点字符 } const INF int = 1e18 e := func() E { return E{} } op := func(a, b E) E { res := E{lc: a.lc, rc: b.rc, size: a.size + b.size} if a.rc == b.lc { res.preMax = a.preMax if a.preMax == a.size { res.preMax += b.preMax } res.sufMax = b.sufMax if b.sufMax == b.size { res.sufMax += a.sufMax } res.max = max(max(a.max, b.max), a.sufMax+b.preMax) } else { res.preMax = a.preMax res.sufMax = b.sufMax res.max = max(a.max, b.max) } return res } n := len(s) seg := NewRadixTree(e, op, -1) seg.Build(n, func(i int) E { return E{1, 1, 1, 1, s[i], s[i]} }) res := make([]int, len(queryIndices)) for i := 0; i < len(queryIndices); i++ { pos := queryIndices[i] char := queryCharacters[i] seg.Set(pos, E{1, 1, 1, 1, char, char}) res[i] = seg.QueryAll().max } return res } // 多级分块结构的隐式树,用于查询区间聚合值. // 可以传入log来控制每个块的大小,以平衡时间与空间复杂度. // log=1 => 线段树,log=10 => 朴素分块. // golang 用于内存管理的 pageAlloc 基数树中,log=3. type RadixTree[E any] struct { e func() E op func(a, b E) E log int blockSize int n int layers [][]E // layers[k][i] 表示第k层第i个块的聚合值. layerShifts []int // layers[k] 表示第k层的块大小为1<<layerShifts[k]. } // log: 每个块的大小B=1<<log.默认log=3. // e: 幺元. // op: 结合律. func NewRadixTree[E any](e func() E, op func(a, b E) E, log int) *RadixTree[E] { if log < 1 { log = 3 } return &RadixTree[E]{ e: e, op: op, log: log, blockSize: 1 << log, } } func (m *RadixTree[E]) Build(n int, f func(i int) E) { m.n = n level0 := make([]E, n) for i := 0; i < n; i++ { level0[i] = f(i) } m.layers = [][]E{level0} m.layerShifts = []int{0} build := func(pre []E) []E { cur := make([]E, (len(pre)+m.blockSize-1)>>m.log) for i := range cur { start := i << m.log end := min(start+m.blockSize, len(pre)) v := pre[start] for j := start + 1; j < end; j++ { v = m.op(v, pre[j]) } cur[i] = v } return cur } preLevel := level0 preShift := 1 for len(preLevel) > 1 { curLevel := build(preLevel) m.layers = append(m.layers, curLevel) m.layerShifts = append(m.layerShifts, m.log*preShift) preLevel = curLevel preShift++ } } func (m *RadixTree[E]) QueryRange(l, r int) E { if l < 0 { l = 0 } if r > m.n { r = m.n } if l >= r { return m.e() } if l == 0 && r == m.n { return m.QueryAll() } res := m.e() i := l for i < r { jumped := false // 从最高层开始尝试找到最大的对齐块 for k := len(m.layerShifts) - 1; k >= 0; k-- { blockSize := 1 << m.layerShifts[k] if i&(blockSize-1) == 0 && i+blockSize <= r { res = m.op(res, m.layers[k][i>>m.layerShifts[k]]) i += blockSize jumped = true break } } if !jumped { res = m.op(res, m.layers[0][i]) i++ } } return res } func (m *RadixTree[E]) QueryAll() E { if len(m.layers) == 0 { return m.e() } return m.layers[len(m.layers)-1][0] } func (m *RadixTree[E]) Get(i int) E { if i < 0 || i >= m.n { return m.e() } return m.layers[0][i] } // O(1). func (m *RadixTree[E]) GetAll() []E { return m.layers[0] } // A[i] = op(A[i], v). func (m *RadixTree[E]) Update(i int, v E) { if i < 0 || i >= m.n { return } m.layers[0][i] = m.op(m.layers[0][i], v) pre := m.layers[0] for k := 1; k < len(m.layers); k++ { bid := i >> m.layerShifts[k] start := bid << m.log end := min(start+m.blockSize, len(pre)) cur := pre[start] for j := start + 1; j < end; j++ { cur = m.op(cur, pre[j]) } m.layers[k][bid] = cur pre = m.layers[k] } } // A[i] = v. func (m *RadixTree[E]) Set(i int, v E) { if i < 0 || i >= m.n { return } m.layers[0][i] = v pre := m.layers[0] for k := 1; k < len(m.layers); k++ { bid := i >> m.layerShifts[k] start := bid << m.log end := min(start+m.blockSize, len(pre)) cur := pre[start] for j := start + 1; j < end; j++ { cur = m.op(cur, pre[j]) } m.layers[k][bid] = cur pre = m.layers[k] } } // 返回最大的 r,使得区间 [l, r) 的聚合值满足 f. // O(logN). func (rt *RadixTree[E]) MaxRight(left int, predicate func(E) bool) int { if left == rt.n { return rt.n } res := rt.e() i := left for i < rt.n { jumped := false // 尝试利用整块跳跃 for k := len(rt.layerShifts) - 1; k >= 0; k-- { blockSize := 1 << rt.layerShifts[k] if i&(blockSize-1) == 0 && i+blockSize <= rt.n { cand := rt.op(res, rt.layers[k][i>>rt.layerShifts[k]]) if predicate(cand) { res = cand i += blockSize jumped = true break } } } if !jumped { res = rt.op(res, rt.layers[0][i]) if !predicate(res) { return i } i++ } } return rt.n } // MinLeft 返回最小的 l,使得区间 [l, r) 的聚合值满足 f. // O(logN). func (rt *RadixTree[E]) MinLeft(right int, predicate func(E) bool) int { if right == 0 { return 0 } res := rt.e() i := right - 1 for i >= 0 { jumped := false for k := len(rt.layerShifts) - 1; k >= 0; k-- { blockSize := 1 << rt.layerShifts[k] // 判断当前下标是否正好为某块的最右端 if (i+1)&(blockSize-1) == 0 && i+1-blockSize >= 0 { cand := rt.op(rt.layers[k][(i+1-blockSize)>>rt.layerShifts[k]], res) if predicate(cand) { res = cand i -= blockSize jumped = true break } } } if !jumped { res = rt.op(rt.layers[0][i], res) if !predicate(res) { return i + 1 } i-- } } return 0 } func min(a, b int) int { if a < b { return a } return b } func max(a, b int) int { if a > b { return a } return b } // cross checking type naive[E any] struct { e func() E op func(a, b E) E log int n int data []E blockSize int } func newNaive[E any](e func() E, op func(a, b E) E, log int) *naive[E] { if log < 1 { log = 6 } return &naive[E]{e: e, op: op, log: log} } func (m *naive[E]) Build(n int, f func(i int) E) { m.n = n m.blockSize = 1 << m.log m.data = make([]E, n) for i := 0; i < n; i++ { m.data[i] = f(i) } } func (m *naive[E]) QueryRange(l, r int) E { result := m.e() // start with the identity element for i := l; i < r; i++ { result = m.op(result, m.data[i]) } return result } func (m *naive[E]) QueryAll() E { result := m.e() for i := 0; i < m.n; i++ { result = m.op(result, m.data[i]) } return result } func (m *naive[E]) Get(i int) E { return m.data[i] } func (m *naive[E]) GetAll() []E { return m.data } func (m *naive[E]) Update(i int, v E) { m.data[i] = m.op(m.data[i], v) } func (m *naive[E]) Set(i int, v E) { m.data[i] = v } // 二分查询最大的 right 使得切片 [left:right] 内的值满足 predicate func (m *naive[E]) MaxRight(l int, f func(E) bool) int { sum := m.e() for i := l; i < m.n; i++ { sum = m.op(sum, m.data[i]) if !f(sum) { return i } } return m.n } // 二分查询最小的 left 使得切片 [left:right] 内的值满足 predicate func (m *naive[E]) MinLeft(r int, f func(E) bool) int { sum := m.e() for i := r - 1; i >= 0; i-- { sum = m.op(m.data[i], sum) if !f(sum) { return i + 1 } } return 0 } func test() { e := func() int { return 0 } op := func(a, b int) int { return max(a, b) } N := rand.Intn(1000) + 1 randNums := make([]int, N) for i := 0; i < N; i++ { randNums[i] = rand.Intn(1000) } rt1 := NewRadixTree(e, op, -1) rt1.Build(N, func(i int) int { return randNums[i] }) rt2 := newNaive(e, op, -1) rt2.Build(N, func(i int) int { return randNums[i] }) Q := int(1e4) for i := 0; i < Q; i++ { op := rand.Intn(9) switch op { case 0: l, r := rand.Intn(N), rand.Intn(N) if rt1.QueryRange(l, r) != rt2.QueryRange(l, r) { panic("err QueryRange") } case 1: if r1, r2 := rt1.QueryAll(), rt2.QueryAll(); r1 != r2 { fmt.Println(rt1.GetAll(), rt2.GetAll()) panic(fmt.Sprintf("err QueryAll: %v %v", r1, r2)) } case 2: i := rand.Intn(N) v := rand.Intn(100) rt1.Update(i, v) rt2.Update(i, v) case 3: i := rand.Intn(N) v := rand.Intn(100) rt1.Set(i, v) rt2.Set(i, v) case 4: // Get i := rand.Intn(N) if rt1.Get(i) != rt2.Get(i) { panic("err Get") } case 5: // GetAll nums1, nums2 := rt1.GetAll(), rt2.GetAll() if slices.Compare(nums1, nums2) != 0 { panic("err GetAll") } case 6: // QueryAll if rt1.QueryAll() != rt2.QueryAll() { panic("err QueryAll") } case 7: // MaxRight l := rand.Intn(N) f := func(x int) bool { return x < 500 } if rt1.MaxRight(l, f) != rt2.MaxRight(l, f) { panic("err MaxRight") } case 8: // MinLeft r := rand.Intn(N) f := func(x int) bool { return x < 500 } if rt1.MinLeft(r, f) != rt2.MinLeft(r, f) { panic("err MinLeft") } } } } func testTime() { e := func() int { return 0 } op := func(a, b int) int { return a + b } N := int(2e5) randNums := make([]int, N) for i := 0; i < N; i++ { randNums[i] = rand.Intn(1000) } time1 := time.Now() rt1 := NewRadixTree(e, op, 3) rt1.Build(N, func(i int) int { return randNums[i] }) for i := 0; i < N; i++ { rt1.QueryRange(i, N) rt1.QueryAll() rt1.Get(i) rt1.Set(i, i) rt1.MaxRight(i, func(x int) bool { return x < int(1e18) }) rt1.MinLeft(i, func(x int) bool { return x < int(1e18) }) } time2 := time.Now() fmt.Println("RadixTree:", time2.Sub(time1)) }