Dado un árbol enraizado desequilibrado, ¿cómo reemplazaría el valor de cada nodo con la suma de todos los valores en su subárbol que son más pequeños que el valor del nodo?

Contestaré mi propia pregunta. Se encontró una manera de hacer esto en [math] O (n \ log n) [/ math] time y [math] O (n) [/ math] memoria adicional.

Asumiré sin pérdida de generalidad que estamos tratando con un árbol binario.
Además, considere que la magnitud de los valores del nodo de árbol es [matemática] O (n) [/ matemática]. Si no, use una de las estrategias descritas al final (*).

Cree un árbol indexado binario auxiliar (BIT) y realice un recorrido de orden posterior del árbol dado para actualizar. Para cada nodo

  1. Calcule la suma de los valores insertados en el BIT que son menores que el valor del nodo actual. Llame a esto sum_before.
  2. Actualice los hijos de este nodo de forma recursiva y reutilice el BIT actual.
  3. Agregue el valor del nodo actual al BIT.
  4. Actualice el valor del nodo actual a la suma de valores en el BIT menor que el valor actual – sum_before.

El BIT solo contendrá valores en el árbol original. Además, al guardar sum_before , descartamos los valores agregados en otras ramas del árbol, considerando solo los valores agregados en el subárbol del nodo actual.

Para cada nodo, hacemos dos operaciones de Lectura y una de Actualización en el BIT. Cada uno toma [math] O (\ log n) [/ math]. Entonces, la complejidad de tiempo general del algoritmo es [matemática] O (n \ log n) [/ matemática]. El BIT utiliza memoria adicional [matemática] O (n) [/ matemática].

Implementación de muestra en C ++:

struct BITree {
vector tree;
int size; BITree(int n = 10) : tree(vector(n, 0)), size(n) {} void Update(int x, int value) {
for (; x < size; x += x & -x)
tree[x] += value;
}
int Read(int x) {
int sum = 0;
for (; x > 0; x -= x & -x)
sum += tree[x];
return sum;
}
}; void TreeUpdate(Node* cur, BITree* bit) {
if (!cur)
return;
int sum_before = bit->Read(cur->value-1);
TreeUpdate(cur->left, bit);
TreeUpdate(cur->right, bit);
bit->Update(cur->value, cur->value);
cur->value = bit->Read(cur->value-1) - sum_before;
}

struct BITree {
vector tree;
int size; BITree(int n = 10) : tree(vector(n, 0)), size(n) {} void Update(int x, int value) {
for (; x < size; x += x & -x)
tree[x] += value;
}
int Read(int x) {
int sum = 0;
for (; x > 0; x -= x & -x)
sum += tree[x];
return sum;
}
}; void TreeUpdate(Node* cur, BITree* bit) {
if (!cur)
return;
int sum_before = bit->Read(cur->value-1);
TreeUpdate(cur->left, bit);
TreeUpdate(cur->right, bit);
bit->Update(cur->value, cur->value);
cur->value = bit->Read(cur->value-1) - sum_before;
}

struct BITree {
vector tree;
int size; BITree(int n = 10) : tree(vector(n, 0)), size(n) {} void Update(int x, int value) {
for (; x < size; x += x & -x)
tree[x] += value;
}
int Read(int x) {
int sum = 0;
for (; x > 0; x -= x & -x)
sum += tree[x];
return sum;
}
}; void TreeUpdate(Node* cur, BITree* bit) {
if (!cur)
return;
int sum_before = bit->Read(cur->value-1);
TreeUpdate(cur->left, bit);
TreeUpdate(cur->right, bit);
bit->Update(cur->value, cur->value);
cur->value = bit->Read(cur->value-1) - sum_before;
}

struct BITree {
vector tree;
int size; BITree(int n = 10) : tree(vector(n, 0)), size(n) {} void Update(int x, int value) {
for (; x < size; x += x & -x)
tree[x] += value;
}
int Read(int x) {
int sum = 0;
for (; x > 0; x -= x & -x)
sum += tree[x];
return sum;
}
}; void TreeUpdate(Node* cur, BITree* bit) {
if (!cur)
return;
int sum_before = bit->Read(cur->value-1);
TreeUpdate(cur->left, bit);
TreeUpdate(cur->right, bit);
bit->Update(cur->value, cur->value);
cur->value = bit->Read(cur->value-1) - sum_before;
}

(*) Si los valores pueden ser negativos o mucho mayores que n, podemos hacer un paso de preprocesamiento para asignar cada valor a un número entero en el rango [1, n]. Podemos hacer esto agregando todos los valores en una matriz, ordenándolos y luego usando un mapa hash.

Otra opción es extender un árbol de búsqueda binario balanceado o un árbol de segmentos que permita consultar la suma de valores hasta X.

Esto funciona, pero afaics es [math] O (n ^ 2) [/ math].

case class Node(value:Int, children:List[Node])

actualización de def (n: Nodo): Nodo = {
paso de definición (v: Int, r: List [Node]): Int = {
r.map (
(n: Nodo) => paso (v, n.children) +
(if (n.value ).suma
}

Nodo (paso (n.value, n.children), n.children.map (update (_)))
}

More Interesting

Cómo usar el hash para el problema de la suma de tripletas

¿Cómo escribirías el código para encontrar la tarjeta faltante del mazo en una complejidad mejor que O (n)?

¿Cuáles son los hitos que puedo mantener para convertirme en un programador exitoso, para seguir comprobando si estoy en el camino correcto o si estoy haciendo las cosas lo suficientemente rápido?

¿Cómo prepararme efectivamente para mi entrevista en C ++? Soy un chico con más de 10 años de experiencia. ¿Dónde puedo encontrar buen material en línea?

Si hay una matriz que contiene N números, cuyo rango es de 1 a N + 1, y solo puedo usar el espacio O (1) y no puedo modificar la matriz, ¿puedo encontrar cualquier número repetido no peor que O (NlogN) ¿hora?

¿Hay algún instituto que lo capacite para descifrar entrevistas tecnológicas difíciles como Google / Amazon / Microsoft?

¿Cómo es la entrevista en Pandora, CA?

Dada una matriz arr [0 ... n-1], ¿cómo calculo arr_low [0 ... n-1] eficientemente st arr_low [i] = número de elementos menor o igual que arr [i] en arr [i + 1 ... n-1]?

¿Qué tipo de preguntas se harán durante las entrevistas de TI para otros estudiantes de la rama?

Llamaremos a un número "número agregado" si este número tiene el siguiente atributo: al igual que los números de Fibonacci 1,1,2,3,5,8,13 ... los dígitos del número pueden dividirse en varias partes, y la parte posterior es la suma de las partes anteriores.

¿Por qué la mayoría de los entrevistadores están obsesionados con los árboles y los gráficos?

¿Cuál es el propósito de la pregunta 'cuál fue su error más difícil' en las entrevistas para puestos de ingeniería de software?

¿Cuáles son algunas preguntas y recursos para mi entrevista de Dropbox?

¿Cuál es el algoritmo más eficiente y fácil (en términos de implementación) para la coincidencia de patrones en una cadena?

[Entrevista de diseño del sistema]: ¿Cuáles son las preguntas populares sobre el diseño del sistema que se hacen a los desarrolladores senior en compañías como Google o Facebook?