Index-based approach is the right call for most real problems. I do this constantly in game engines and graph processing, and it's faster than Rc<RefCell> anyway since you get cache locality.
The borrow checker isn't fighting you here, it's actually protecting you from aliasing bugs that are trivial to create with raw pointers. Once you accept that Rust doesn't want you holding multiple mutable references to the same data, indices just click.
Only reach for Rc<RefCell> if you truly need shared ownership across threads or when building something like a DOM where you don't control traversal order. Otherwise you're just paying runtime costs for a problem you don't have.