Всем привет!
Не так давно я решил задачу COT2.
В этой задаче нам дано дерево. Каждому дереву соответствует число. Нужно быстро отвечать на запрос x y
— кол-во различных чисел на пути от вершины x
до вершины y
.
Сначала я написал на неё, как мне казалось верное решение, но оно было не верным, но оно зашло.
Вот это решение — http://pastie.org/8667428.
Идея его была такова:
Обойдем дерево dfs'ом и сохраним все вершины в порядке обхода. Обход назовем v[]
. Потом чуть переделаем наши запросы:
Вместо (x,y)
будет (l,r)
, где l
и r
позиции вершин x
и y
в нашем обходе v[]
. Если l>r
, то поменяем l
и r
местами.
Теперь применим корневую эвристику к запросам, то есть отсортируем запросы по паре (l/block,r)
, где block ~ sqrt(n)
.
Теперь будем обрабатывать наши запросы в отсортированном порядке.
То есть, если мы сейчас на пути v[old_l]->v[old_r]
и нам надо перейти на путь v[l]->v[r]
, то мы просто двигаемся по дереву от вершины old_l
до вершины l
и от вершины old_r
до вершины r
. При этом, каждый раз посещая какую-нибудь вершину, мы проверяем: лежит ли она на пути v[l]->v[r]
, если лежит, то проверяем ложили ли мы число этой вершины в ответ, если нет, то ложим(ложить будем числа за O(1)
применяя обычный массив меток).
Это есть мое первое решение. Оно зашло, хоть оно неверное. Так как для него есть хороший контр-тест, который дает асимптотику O(N*M)
.
Этот тест будет таким:
1
/|\
/ 2 \
| |
| |
. .
. .
. .
(n/2) (n)
А запросы будут такого вида:
(n/2,n/2+1), (2,n/2+2), (n/2,n/2+3), ..., (2,n)
Это будет худшим случаем для данного решения, так как мы построим такой обход:
v[]={ 1, 3, 4, 5, ..., n/2, 2, n/2+1, n/2+2, ..., n }
И вершины n/2
и 2
будут находиться рядом, но вот расстояние между ними будет O(N)
, и если мы будем обрабатывать запросы, в которых мы должны будем переходить на такое расстояние, то будет сложность решения O(N*M)
.
Но чуть позже я придумал верное решение. Оно отличается от первого решения совсем немного.
Вот код этого решения — http://pastie.org/8667490.
Мы должны поменять обход, чтобы расстояние между соседними вершинами в обходе было O(1)
. То есть dist(v[i],v[i+1])=O(1)
.
Делать будем его так:
Почти так же, как и обычный обход.
Будем ходить dfs'ом по дереву, когда заходим в вершину, то добавляем её в обход, если она на четной глубине. Когда выходим из вершины, то добавляем её в обход, если она на нечетной глубине.
Из этого видно что расстояние между соседними вершинами будет примерно 3-4, то есть dist(v[i],v[i+1])=O(1)
.
И мы получаем честное решение за O(M sqrt N)
.
Можете рассматривать эту мини-статейку, как разбор к этой задаче :)
Но у меня есть вопрос: Можно ли решить эту задачу с более лучшей асимптотикой, например O(M log N)
или O(M log^2 N)
? Если да, то как её решить с более лучшей асимптотикой?