Skip to content

Commit b79ac6f

Browse files
committed
Faster approach only traversing tree as much as needed
1 parent 0eba642 commit b79ac6f

File tree

2 files changed

+113
-68
lines changed

2 files changed

+113
-68
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ pie
6565
"Year 2016" : 663
6666
"Year 2020" : 286
6767
"Year 2015" : 87
68-
"Years 2019, 2021 and 2022" : 47
68+
"Years 2019, 2021 and 2022" : 45
6969
```
7070

71-
* [2022](#2022) (14 ms)
71+
* [2022](#2022) (12 ms)
7272
* [2021](#2021) (11 ms)
7373
* [2020](#2020) (286 ms)
7474
* [2019](#2019) (22 ms)
@@ -81,7 +81,7 @@ pie
8181
%%{init: {"themeVariables": { "pie1": "#7cb5ec", "pie2": "#90ed7d", "pie3": "#f7a35c", "pie4": "#c6cdd5"}}}%%
8282
pie
8383
title Year 2022 benchmark time by % of total
84-
"Day 20" : 7449
84+
"Day 20" : 5067
8585
"Day 11" : 2386
8686
"Day 23" : 2017
8787
"Others" : 2029
@@ -108,7 +108,7 @@ pie
108108
| 17 | [Pyroclastic Flow](https://adventofcode.com/2022/day/17) | [Source](src/year2022/day17.rs) | 68 |
109109
| 18 | [Boiling Boulders](https://adventofcode.com/2022/day/18) | [Source](src/year2022/day18.rs) | 129 |
110110
| 19 | [Not Enough Minerals](https://adventofcode.com/2022/day/19) | [Source](src/year2022/day19.rs) | 407 |
111-
| 20 | [Grove Positioning System](https://adventofcode.com/2022/day/20) | [Source](src/year2022/day20.rs) | 7449 |
111+
| 20 | [Grove Positioning System](https://adventofcode.com/2022/day/20) | [Source](src/year2022/day20.rs) | 5067 |
112112
| 21 | [Monkey Math](https://adventofcode.com/2022/day/21) | [Source](src/year2022/day21.rs) | 61 |
113113
| 22 | [Monkey Map](https://adventofcode.com/2022/day/22) | [Source](src/year2022/day22.rs) | 132 |
114114
| 23 | [Unstable Diffusion](https://adventofcode.com/2022/day/23) | [Source](src/year2022/day23.rs) | 2017 |

src/year2022/day20.rs

+109-64
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ use crate::util::iter::*;
22
use crate::util::parse::*;
33
use std::ops::{Index, IndexMut};
44

5-
#[derive(Clone, Copy)]
5+
#[derive(Clone, Copy, Default)]
66
struct Node {
77
size: u16,
88
left: u16,
99
right: u16,
1010
up: u16,
1111
}
1212

13-
struct Tree {
13+
struct OrderStatisticTree {
1414
root: u16,
15-
size: i64,
15+
size: u16,
1616
nodes: Vec<Node>,
1717
}
1818

19-
impl Index<u16> for Tree {
19+
impl Index<u16> for OrderStatisticTree {
2020
type Output = Node;
2121

2222
#[inline]
@@ -25,27 +25,27 @@ impl Index<u16> for Tree {
2525
}
2626
}
2727

28-
impl IndexMut<u16> for Tree {
28+
impl IndexMut<u16> for OrderStatisticTree {
2929
#[inline]
3030
fn index_mut(&mut self, index: u16) -> &mut Self::Output {
3131
&mut self.nodes[index as usize]
3232
}
3333
}
3434

35-
impl Tree {
36-
fn from(input: &[i64]) -> Tree {
37-
let mut size = input.len();
35+
impl OrderStatisticTree {
36+
fn from(size: usize) -> Self {
3837
let mut start = 0;
3938
let mut end = size;
39+
let mut level = size;
4040

41-
let mut remaining = None;
4241
let mut nodes = Vec::with_capacity(size * 2);
42+
let mut remaining = None;
4343

4444
let empty = u16::MAX;
45-
let leaf = Node { size: 1, left: empty, right: empty, up: empty };
45+
let leaf = Node { size: 1, ..Default::default() };
4646
nodes.resize(size, leaf);
4747

48-
while size > 0 {
48+
while level > 0 {
4949
let mut push = |left: usize, right: usize| {
5050
let index = nodes.len() as u16;
5151
nodes[left].up = index;
@@ -59,7 +59,7 @@ impl Tree {
5959
push(left, right);
6060
}
6161

62-
if size % 2 == 1 {
62+
if level % 2 == 1 {
6363
if let Some(right) = remaining {
6464
remaining = None;
6565
push(end - 1, right);
@@ -70,13 +70,13 @@ impl Tree {
7070

7171
start = end;
7272
end = nodes.len();
73-
size = end - start;
73+
level = end - start;
7474
}
7575

76-
Tree { root: (end - 1) as u16, size: (input.len() - 1) as i64, nodes }
76+
OrderStatisticTree { root: (end - 1) as u16, size: (size - 1) as u16, nodes }
7777
}
7878

79-
fn position(&self, start: usize) -> u16 {
79+
fn position(&self, start: usize) -> usize {
8080
let mut cur = start as u16;
8181
let mut offset = 0;
8282

@@ -89,12 +89,12 @@ impl Tree {
8989
cur = next;
9090
}
9191

92-
offset
92+
offset as usize
9393
}
9494

95-
fn value_at(&self, start: u16) -> usize {
95+
fn value_at(&self, start: usize) -> usize {
9696
let mut cur = self.root;
97-
let mut offset = start;
97+
let mut offset = start as u16;
9898

9999
loop {
100100
let Node { size, left, right, .. } = self[cur];
@@ -114,71 +114,116 @@ impl Tree {
114114
}
115115

116116
fn mix(&mut self, start: usize, value: i64) {
117-
let start = start as u16;
118-
let mut cur = start;
119-
let mut offset = 0;
117+
let mut delta_right = value.rem_euclid(self.size as i64) as u16;
118+
let mut delta_left = self.size - delta_right;
120119

121-
while cur != self.root {
122-
let next = self[cur].up;
123-
let Node { left, right, .. } = self[next];
124-
125-
if right == cur {
126-
offset += self[left].size;
127-
};
128-
self[next].size -= 1;
129-
cur = next;
120+
if delta_left == 0 || delta_right == 0 {
121+
return;
130122
}
131123

124+
// Temporarily set our size to zero
125+
let start = start as u16;
126+
self[start].size = 0;
127+
132128
let parent = self[start].up;
129+
let mut dest = parent;
133130

134-
if parent == self.root {
135-
if self[self.root].left == start {
136-
self.root = self[self.root].right;
137-
} else {
138-
self.root = self[self.root].left;
131+
// Go up
132+
let (left, right) = loop {
133+
let Node { left, right, up, .. } = self[dest];
134+
let left_size = self[left].size;
135+
let right_size = self[right].size;
136+
137+
if delta_left <= left_size || delta_right <= right_size {
138+
break (left, right);
139139
}
140-
} else {
141-
let grand_parent = self[parent].up;
142-
let next_parent =
143-
if self[parent].left == start { self[parent].right } else { self[parent].left };
144-
self[next_parent].up = grand_parent;
145-
if self[grand_parent].left == parent {
146-
self[grand_parent].left = next_parent;
140+
141+
if self[up].left == dest {
142+
delta_right -= right_size;
143+
delta_left += right_size;
147144
} else {
148-
self[grand_parent].right = next_parent;
145+
delta_right += left_size;
146+
delta_left -= left_size;
149147
}
150-
}
151148

152-
cur = self.root;
153-
offset = (offset as i64 + value).rem_euclid(self.size) as u16;
149+
self[dest].size -= 1;
150+
dest = up;
151+
};
154152

155-
loop {
156-
let Node { size, left, right, up } = self[cur];
153+
let (left, right) = if delta_left <= self[left].size {
154+
// Down left
155+
dest = left;
157156

158-
if size == 1 {
159-
self[parent] = Node { size: 2, left: start, right: cur, up };
157+
loop {
158+
let Node { size, left, right, .. } = self[dest];
160159

161-
self[cur].up = parent;
162-
self[start].up = parent;
160+
if size == 1 {
161+
break (start, dest);
162+
}
163163

164-
if self[up].left == cur {
165-
self[up].left = parent;
164+
self[dest].size += 1;
165+
let right_size = self[right].size;
166+
167+
if delta_left <= right_size {
168+
dest = right;
166169
} else {
167-
self[up].right = parent;
170+
delta_left -= right_size;
171+
dest = left;
168172
}
173+
}
174+
} else {
175+
// Down right
176+
dest = right;
177+
178+
loop {
179+
let Node { size, left, right, .. } = self[dest];
180+
181+
if size == 1 {
182+
break (dest, start);
183+
}
184+
185+
self[dest].size += 1;
186+
let left_size = self[left].size;
169187

170-
break;
188+
if delta_right <= left_size {
189+
dest = left;
190+
} else {
191+
delta_right -= left_size;
192+
dest = right;
193+
}
171194
}
195+
};
172196

173-
self[cur].size += 1;
174-
let size = self[left].size;
175-
if offset < size {
176-
cur = left;
197+
// Remove node
198+
let sibling =
199+
if self[parent].left == start { self[parent].right } else { self[parent].left };
200+
201+
if parent == self.root {
202+
self[sibling].size += 1;
203+
self.root = sibling;
204+
} else {
205+
let grand_parent = self[parent].up;
206+
self[sibling].up = grand_parent;
207+
208+
if self[grand_parent].left == parent {
209+
self[grand_parent].left = sibling;
177210
} else {
178-
cur = right;
179-
offset -= size;
211+
self[grand_parent].right = sibling;
180212
}
181213
}
214+
215+
// Insert node
216+
let up = self[dest].up;
217+
218+
if self[up].left == dest {
219+
self[up].left = parent;
220+
} else {
221+
self[up].right = parent;
222+
}
223+
224+
self[parent] = Node { size: 2, left, right, up };
225+
self[left] = Node { size: 1, up: parent, ..Default::default() };
226+
self[right] = Node { size: 1, up: parent, ..Default::default() };
182227
}
183228
}
184229

@@ -195,7 +240,7 @@ pub fn part2(input: &[i64]) -> i64 {
195240
}
196241

197242
fn decrypt(input: &[i64], key: i64, rounds: usize) -> i64 {
198-
let mut tree = Tree::from(input);
243+
let mut tree = OrderStatisticTree::from(input.len());
199244

200245
for _ in 0..rounds {
201246
for (i, n) in input.iter().enumerate() {
@@ -207,7 +252,7 @@ fn decrypt(input: &[i64], key: i64, rounds: usize) -> i64 {
207252
let zeroth = tree.position(start);
208253
[1000, 2000, 3000]
209254
.iter()
210-
.map(|offset| tree.value_at((zeroth + offset) % (input.len() as u16)))
255+
.map(|offset| tree.value_at((zeroth + offset) % input.len()))
211256
.map(|index| input[index] * key)
212257
.sum()
213258
}

0 commit comments

Comments
 (0)