Due to the circumstances, normalization wasn't an efficient option. I ended up throwing together a barebones tree with a 5-line DFS implementation to traverse it. It handled inserts, updates and deletions (for my use-case) in linear time.
The details aren't so important as the fact that adding a dependency would have been overkill for my needs. This isn't to say that efficient graph implementation libraries should not exist or be used, but I was able to produce this code faster by having that basic CS knowledge.