You might want to use an order statistic tree, a tree data structure that supports O(log n) insertions, deletions, and lookups. Typically, order statistic trees are used to store sorted data, though it is relatively straightforward to modify them to store an unsorted sequence.
Intuitively, an order statistic tree is a binary tree where each node stores the number of children in its left subtree. That way, you can recursively look up the nth element as follows:
- If the tree is null, there is no element.
- If n is less than or equal to the number of elements in the left subtree (call it I), recursively look up the element in the left subtree.
- If n = k + 1, the root of the tree is the nth element.
- Otherwise, look up the n - k - 1st element in the right subtree.
To do an insertion before node n, use this same procedure to find the nth node and insert the new value as that nodes inorder predecessor (go left, then keep going right until you walk off the tree and insert the node there). Then walk back up the tree from nth element upward and adjust the value of k for all nodes on the insertion path that need to be updated.
To prevent the tree from getting too imbalance, you can use any standard tree balancing scheme (AVL, red/black, etc.) to keep the height at O(log n). This gives O(log n) performance for all the operations on the data structure.
Hope this helps!