架子上有盒子,每个盒子都有一个与之关联的ID号。有Q查询。
每个查询都采用l r
形式,并通过将包含范围内的所有框移动到工具架的头部(正面)来执行查询。
鉴于查询和所有方框的初始排序,您能在货架上找到方框ID的最终订购吗?
示例输入:
6
1 2 3 4 5 6
3
4 5
3 4
2 3
示例输出:
2 4 1 5 3 6
说明:
架子最初看起来像这样:[1,2,3,4,5,6]
。我们按以下顺序执行查询:
[4,5,1,2,3,6]
[1,2,4,5,3,6]
[2,4,1,5,3,6]
然后我们打印这个ID号的最终排序作为我们的答案。
有没有比O(Q*N)
更好的解决方案?
答案 0 :(得分:3)
(另见Kundor对Onaka如何使用类似treap结构(How does a treap help to update this ordered queue?)的出色解释。)
rope结构可以允许O(m log n)
时间解决方案。除了根之外,二叉树中的每个节点都存储其左子树的权重;在我们的例子中,权重是元素的数量。我们列表的当前顺序从左到右存储在叶子中。
可以通过跟随节点在ith to jth
时间内访问包含当前O(log n)
元素的子树:如果i
小于节点权重,则向左;否则,从i
减去左侧节点的权重,然后向右移动。
要移动元素,请拆分包含它们的子树(更新侧边),并将拆分部分与树的前部连接起来。您可能需要考虑如何使树保持合理平衡。
以下示例将元素的索引存储在原始列表中(非零),而不是元素本身,以允许范围条目(例如,1-3):
input [1,2,3,4,5,6]
rope 6
(1-6)
1. Move 4th-5th to front:
2 | 3 | 1
split (4-5) | (1-3) | (6)
concat 6
5
2 1
(4-5) (1-3) (6)
2. Move 3rd-4th to front:
split 4 |
3 |
2 1 | 2
(4-5) (3) (6) | (1-2)
concat 6
2 3
(1-2) 2 1
(4-5) (3) (6)
3. Move 2nd-3rd to front:
split 4 |
2 2 |
(1) 1 1 | 2
(5) (3) (6) | (2,4)
concat 6
3
2 2
2 1 1 1
(2,4) (1) (5) (3) (6)
答案 1 :(得分:0)
正如Gassa指出的那样,你可以使用一个splay树。
在(未经测试!)C中,结构看起来像
// 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
};
一些基本的操作例程:
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;
}
不寻常的部分是按索引找到一个方框:
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;
}
}
并对盒子顺序进行手术:
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
}
答案 2 :(得分:0)
对此有一个相当简单的实际解决方案。
它基于在保持索引数组的同时将数字附加到原始数据,[拾取次数]次。然后使用该索引数组从数据中获取结果。
这个想法是在数组的右侧工作,因为大多数系统支持有效的追加。或者,可以从开始将[2 *选择数]零添加到数据中,然后再填充。
这需要镜像原始数据。
伪:
data = 6 5 4 3 2 1 // Mirrored original data, an integer array, will increase in size
ind = 6 5 4 3 2 1 // A fixed size, length-6 (tot nr of picks) integer array
picks = (5 4) // Row 1 - mirrored 2-column (and 3 row in this example) table
(4 3) // Row 2
(3 2) // Row 3
s = 6 // 6 is the total number of picks, ie. 2 * 3 (cols * rows)
:For row :In 1 2 3 // Loop through the pick rows
a = 1 + s - picks[row;] // a is now a 2-element array, as picks[row] is 2 elements
data ,= data[a] // Adding 2 elements to data per each cycle
s += 2
ind[data[a]] = (s - 1), s // 2 elements of ind get assigned (overwritten) here
:End
// Grab the result
// data is now: 6 5 4 3 2 1 5 4 2 1 4 2
// ind is now: 10 12 4 11 7 1
order = [grab the ascending sort order of ind] // Will be 6 3 5 1 4 2 in this example
result = data[ind[order]] // Will be 6 3 5 1 4 2
result = [reverse of] result // Will be 2 4 1 5 3 6
有一种替代方法可以获取结果,其中不需要索引维护(即.ind变量)或排序:
// Grab the result 2:
result = [unique] [mirror of] data
Imho,没有魔法可以得到结果。这个解决方案与选择数量的比例非常相称。