#include <stdio.h>
#include <stdlib.h>
/*
/*
这个文件是 C 和 Markdown。
你要找的数据结构需要回答“三面
范围查询”。它们被称为三面,因为你可以想象
您的数组表示二维集中的 n 个点,其中
x 坐标是数组索引,y 坐标是值
在那个索引处;然后,您的查询相当于“打印所有 y
i X" 的点 (x,y) 的坐标。这是
打印值的三个不等式。
一种非常简单的数据结构,可以支持三种大小的范围
查询是优先搜索树 (PST)。
*/
typedef struct NODE {
int y_max;
struct NODE *left, *right;
} Node;
/*
对于您的使用,您可以使用一个非常简单的优先级搜索树。这
树将有 2*n - 1 个节点。叶节点与单个关联
数组中的位置。非叶节点与一个连续的
阵列的区域。关联如下:
-
根与整个数组相关联:positions [0, n)
-
范围为 [a,b) 的节点的左子节点与
位置 [a, floor((a + b)/2))
-
范围为 [a,b) 的节点的右子节点与
位置 [floor((a+b)/2), b)
如果区域为空,则不为其存储节点。
关联是隐式的,不存储在任何地方;有可能
从 n 和树的形状推断出来。
每个节点额外存储所有节点中的最大值
值存储在其关联区域中。
例如,如果您的数组是 {60, 70, 80, 90, 100},那么树
节点及其关联的区域和值是:
[0,5):100
/ \
[0,2):70 [2,5):100
/ \ / \
[0,1):60 [1,2):70 [2,3):80 [3,5):100
/ \
[3,4):90 [4,5):100
使用递归构造 PST 需要线性时间:
*/
int Max(int x, int y) { return x > y ? x : y; }
Node * Construct(int n, int ys[]) {
if (!n) return NULL;
Node *result = malloc(sizeof(Node));
if (1 == n) {
result->y_max = ys[n];
result->left = result->right = NULL;
} else {
// To find y_max, we first recurse:
result->left = Construct(n / 2, ys);
result->right = Construct(n - n / 2, ys + n / 2);
// The the y_max is the max of the child y_max values:
result->y_max = Max(result->left->y_max, result->right->y_max);
}
return result;
}
/*
要查询 PST,您需要找到树的所有叶子
给定的[i, j] 区域和y_max > X。这也可以做到
递归:
*/
void Query(int a, int b, Node *pst, int i, int j, int X) {
if (!pst || a > j || b < i || pst->y_max <= X) return;
if (b - a == 1) printf("%d ", pst->y_max);
Query(a, (a + b) / 2, pst->left, i, j, X);
Query((a + b) / 2, b, pst->right, i, j, X);
}
/*
仔细计算表明时间复杂度为 O(log n + k),
其中 k 是报告的节点数。请注意,下限
任何支持这些查询的数据结构都是 Ω(k),因为
仅打印结果就需要这么多时间。
你可以通过谷歌搜索“优先级”找到许多仔细的核算
搜索树”。
上面的数据结构在很多方面都不是最优的,但它是
这种方式解释起来很简单。它可以被组织存储在一个
大小为 n/2 + O(1) 的数组,而不是上面的 Θ(n) 树节点。
可以通过遍历树在 O(log n) 时间内执行更新
递归并在备份途中重建y_max:
*/
void Update(int i, int v, int a, int b, Node *pst) {
if (a + 1 == b) {
pst->y_max = v;
return;
}
// Recurse down one subtree:
int mid = (a + b) / 2;
if (i < mid) {
Update(i, v, a, mid, pst->left);
} else {
Update(i, v, mid, b, pst->right);
}
pst->y_max = Max(pst->left->y_max, pst->right->y_max);
}