Сжатое многомерное дерево отрезков — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 6: Строка 6:
  
 
==Структура==
 
==Структура==
Вообще говоря, с поставленной задачей справится и обычное <tex>p</tex>-мерное дерево отрезков. Если дерево строить по всем элементам массива, то запрос операции на <tex>p</tex>-мерном прямоугольнике c помощью такой структуры будет выполняться за <tex>O(\frac{1}{p}log^p\,S)</tex>, а сама структура будет занимать порядка <tex>O(S)</tex> памяти, где <tex>S</tex> количество элементов в <tex>p</tex>-мерном массиве. Если дерево строить по элементам множества <tex>A</tex>, то асимптотики изменятся на <tex>O(log^p\,n)</tex> и <tex>O(n^p)</tex> соответственно. Однако, можно провести следующую оптимизацию — каждый раз дерево отрезков внутри вершины будем строить только по тем элементам множества <tex>A</tex>, которые встречаются в отрезке, за который отвечает эта вершина. Действительно, другие элементы уже были "исключены" и заведомо лежат вне желаемого <tex>p</tex>-мерного прямоугольника. Для этого будем использовать сохранение всего подмассива в каждой вершине дерева отрезков.
+
Для уменьшения количества занимаемой памяти можно провести оптимизацию <tex>p</tex>-мерного дерева отрезков. Для начала, будем использовать дерево отрезков с сохранением всего подотрезка в каждой вершине. Другими словами, в каждой вершине дерева отрезков мы будем хранить не только какую-то сжатую информацию об этом подотрезке, но и все элементы массива, лежащие в этом подотрезке. Казалось бы, это только увеличит объем структуры, но не все так просто. При построении будем действовать следующим образом каждый раз дерево отрезков внутри вершины уже готового дерева будем строить не по всем элементам множества <tex>A</tex>, а только по сохраненному в этой вершине подотрезку. Действительно, зачем строить дерево по всем элементам, когда элементы вне подотрезка уже были "исключены" и заведомо лежат вне желаемого <tex>p</tex>-мерного прямоугольника.
 +
 
 +
Построив дерево отрезков по первой координатедерева отрезков внутри вершины будем строить только по тем элементам множества , которые встречаются в отрезке, за который отвечает эта вершина. Действительно, другие элементы уже были "исключены" и заведомо лежат вне желаемого -мерного прямоугольника.
  
 
==Построение дерева и запрос операции==
 
==Построение дерева и запрос операции==

Версия 10:29, 8 июня 2011

Задача:
Пусть имеется множество [math]A[/math], состоящее из [math]n[/math] взвешенных точек в [math]p[/math]-мерном пространстве. Необходимо быстро отвечать на запрос о суммарном весе точек, находящихся в [math]p[/math]-мерном прямоугольнике [math](x_a,x_b),(y_a,y_b),\,...\,,(z_a,z_b)[/math]

Вообще говоря, с поставленной задачей справится и обычное [math]p[/math]-мерное дерево отрезков. Для этого достаточно на [math]i[/math]-той глубине вложенности строить дерево отрезков по всевозможным [math]i[/math]-тым координатам точек множества [math]A[/math], а при запросе использовать бинарный поиск. Очевидно, запрос будет делаться за [math]O(log^p\,n)[/math] времени, а сама структура данных будет занимать [math]O(n^p)[/math] памяти.

Структура

Для уменьшения количества занимаемой памяти можно провести оптимизацию [math]p[/math]-мерного дерева отрезков. Для начала, будем использовать дерево отрезков с сохранением всего подотрезка в каждой вершине. Другими словами, в каждой вершине дерева отрезков мы будем хранить не только какую-то сжатую информацию об этом подотрезке, но и все элементы массива, лежащие в этом подотрезке. Казалось бы, это только увеличит объем структуры, но не все так просто. При построении будем действовать следующим образом — каждый раз дерево отрезков внутри вершины уже готового дерева будем строить не по всем элементам множества [math]A[/math], а только по сохраненному в этой вершине подотрезку. Действительно, зачем строить дерево по всем элементам, когда элементы вне подотрезка уже были "исключены" и заведомо лежат вне желаемого [math]p[/math]-мерного прямоугольника.

Построив дерево отрезков по первой координатедерева отрезков внутри вершины будем строить только по тем элементам множества , которые встречаются в отрезке, за который отвечает эта вершина. Действительно, другие элементы уже были "исключены" и заведомо лежат вне желаемого -мерного прямоугольника.

Построение дерева и запрос операции

Алгоритм построения такого "усеченного" дерева отрезков будет выглядеть следующим образом:

  • Cоставить массив из всех [math]n[/math] элементов множества [math]A[/math], упорядочить его по первой координате
  • Построить на нём дерево отрезков с сохранением подмассива в каждой вершине
  • Все подмассивы в вершинах получившегося дерева отрезков упорядочить по следующей координате, после чего повторить построение дерева для каждого из них


Псевдокод:

  build_normal_tree(element[] array)
  {
     //построение одномерного дерева отрезков на массиве array с сохранением подмассива в каждой вершине
  }
  
  get_inside_array(vertex)
  {
     //получение подмассива, сохраненного в вершине vertex
  }
  
  build_compressed_tree(element[] array, int coordinate = 0) 
  {
     //собственно, построение сжатого дерева отрезков
     if (coordinate < p) 
     {
        sort(array, coordinate); //сортировка массива по нужной координате
        segment_tree = build_normal_tree(array);
        for (each vertex in segment_tree) 
        {
           build_compressed_tree(inside_array(each), coordinate + 1);
        }
     }
  }

При такой оптимизации асимптотика размера структуры составит [math]O(n\,log^{p-1}\,n)[/math], а запрос будет аналогичен запросу в обычном [math]p[/math]-мерном дереве отрезков за [math]O(log^p\,n)[/math]. Но расплатой станет невозможность делать произвольный запрос модификации: в самом деле, если появится новый элемент, то это приведёт к тому, что мы должны будем в каком-либо дереве отрезков по второй или более координате добавить новый элемент в середину, что эффективно сделать невозможно.

Источники

Дерево отрезков на e-maxx.ru