As Gassa points out, you can use a splay tree for this.
In (untested!) C, the structure would look like
// Splay tree of boxes
struct Box {
struct Box *left; // root of the left subtree
struct Box *right; // root of the right subtree
struct Box *parent;
int left_size; // size of the left subtree
int id; // box id
};
Some basic manipulation routines:
void box_init(struct Box *box, int id) {
box->left = box->right = box->parent = NULL;
box->left_size = 0;
box->id = id;
}
void box_link_left(struct Box *box1, struct Box *box2, int box2_size) {
box1->left = box2;
box1->left_size = box2_size;
if (box2 != NULL) {
box2->parent = box1;
}
}
void box_link_right(struct Box *box1, struct Box *box2) {
box1->right = box2;
if (box2 != NULL) {
box2->parent = box1;
}
}
// Changes
//
// box left
// / \ / \
// left c => a box
// / \ / \
// a b b c
void box_rotate_right(struct Box *box) {
struct Box *left = box->left;
struct Box *parent = box->parent;
if (parent == NULL) {
} else if (parent->left == box) {
parent->left = left;
} else {
parent->right = left;
}
box_link_left(box, left->right, box->left_size - left->left_size - 1);
box_link_right(left, box);
}
void box_rotate_left(struct Box *box) {
// code here
}
void box_splay_to_root(struct Box *box) {
// code to bottom-up splay here
}
struct Box *box_rightmost(struct Box *box) {
while (box->right != NULL) {
box = box->right;
}
return box;
}
The unusual parts are finding a box by index:
struct Box *box_at(struct Box *root, int i) {
struct Box *box = root;
while (1) {
if (i <= box->left_size) {
box = box->left;
continue;
}
i -= box->left_size;
if (i == 1) {
return box;
}
i--;
box = box->right;
}
}
and doing surgery on the box order:
struct Box *box_move_to_front(struct Box *root, int l, int r) {
if (l == 1) { // no-op
return root; // new root
}
struct Box *br = box_at(root, r);
box_splay_to_root(br);
// cut right of br
struct Box *right_of_r = br->right;
br->right = NULL;
struct Box *bl1 = box_at(br, l - 1);
// cut right of bl1
struct Box *mid = bl1->right;
// link
bl1->right = right_of_r;
// link
mid = box_rightmost(mid);
box_splay_to_root(mid);
box_link_right(mid, bl1);
return mid; // new root
}