-
Notifications
You must be signed in to change notification settings - Fork 31
/
PersistentArray-16ary-fast.go
154 lines (134 loc) · 3.44 KB
/
PersistentArray-16ary-fast.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// !可持久化数组(可以越界访问的实现)
// Persistent Array
// Reference: <https://qiita.com/hotman78/items/9c643feae1de087e6fc5>
// <https://maspypy.github.io/library/ds/dynamic_array.hpp>
// - 16叉树
// - Fully persistent
// - `Get(root, k)`: get k-th element
// - `Set(root, k, data)`: make new array whose k-th element is updated to data
package main
import (
"bufio"
"fmt"
"os"
"runtime/debug"
)
// 单组测试时禁用gc
func init() {
debug.SetGCPercent(-1)
}
func main() {
// https://atcoder.jp/contests/abc273/tasks/abc273_e
// 模拟git
// 现在给定一个空数组A 和一系列操作,操作有四种
// 1. ADD x : 在A的末尾添加一个元素x (git commit)
// 2. DELETE : 删除A的末尾元素 (git revert)
// 3. SAVE y : 保存当前数组A的状态到y分支 (git checkout -b)
// 4. LOAD z : 将z分支加载到当前数组A (git merge)
// 每次操作之后输出当前数组A的最后一个元素,如果数组为空则输出-1
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var q int
fmt.Fscan(in, &q)
type pair struct {
ptr int
root *AryNode
}
git := make(map[int]pair)
undefined := int32(-1)
A := NewPersistentArray(undefined)
root := A.Alloc()
ptr := 0
for i := 0; i < q; i++ {
var op string
fmt.Fscan(in, &op)
if op == "ADD" {
var x int32
fmt.Fscan(in, &x)
root = A.Set(root, ptr, x)
ptr++
} else if op == "DELETE" {
if ptr > 0 {
ptr--
}
} else if op == "SAVE" {
var y int
fmt.Fscan(in, &y)
git[y] = pair{ptr, root}
} else if op == "LOAD" {
var z int
fmt.Fscan(in, &z)
ptr, root = git[z].ptr, git[z].root
}
last := A.Get(root, ptr-1)
if last == undefined {
fmt.Fprint(out, -1, " ")
} else {
fmt.Fprint(out, last, " ")
}
}
}
type E = int32
type AryNode struct {
data E
children [16]*AryNode
}
type PersistentArray struct {
null E // 当index越界/不存在时返回的值
}
func NewPersistentArray(null E) *PersistentArray {
return &PersistentArray{null: null}
}
// TODO: pool 优化动态内存分配
func (o *PersistentArray) Alloc() *AryNode {
return &AryNode{data: o.null}
}
func (o *PersistentArray) Build(nums []E) *AryNode {
root := o.Alloc()
for i := 0; i < len(nums); i++ {
root = o.mutableSet(root, i, nums[i])
}
return root
}
func (o *PersistentArray) Get(root *AryNode, index int) E {
if root == nil {
return o.null
}
if index == 0 {
return root.data
}
return o.Get(root.children[index&15], (index-1)>>4)
}
func (o *PersistentArray) Set(root *AryNode, index int, data E) *AryNode {
newNode := o.Alloc()
if root != nil { // copyNode
newNode.data = root.data
for i := 0; i < 16; i++ {
newNode.children[i] = root.children[i]
}
}
if index == 0 {
newNode.data = data
return newNode
}
newNode.children[index&15] = o.Set(newNode.children[index&15], (index-1)>>4, data)
return newNode
}
func (o *PersistentArray) Copy(root *AryNode) *AryNode {
if root == nil {
return nil
}
return &AryNode{data: root.data, children: root.children}
}
func (o *PersistentArray) mutableSet(root *AryNode, index int, data E) *AryNode {
if root == nil {
root = o.Alloc()
}
if index == 0 {
root.data = data
return root
}
root.children[index&15] = o.mutableSet(root.children[index&15], (index-1)>>4, data)
return root
}