После
напряженной недели на работе, жители Манчестера и Ливерпуля решили отправиться
в поход на выходные. Прогуливаясь по лесу, они наткнулись на уникальное дерево,
состоящее из n вершин. Вершины дерева
пронумерованы числами от 1 до n.
Каждой вершине
дерева присвоен один из c возможных цветов. Чтобы побороть скуку, они
решили проверить свои логические навыки. Корнем дерева является вершина 1. Для
каждой вершины они решили найти ближайшего предка, цвет которого совпадает с
цветом этой вершины.
Вход. Первая строка
содержит два целых числа n и c (1 ≤ n, c ≤ 105)
– количество вершин в дереве и количество возможных цветов.
Вторая строка
содержит n – 1 целых чисел, где i-ое число указывает на отца (i + 1) - ой вершины.
Третья строка
содержит n целых чисел, определяющих
цвета вершин. Значения цветов лежат в диапазоне от 1 до c включительно.
Выход. Выведите в
одной строке n чисел, где i-ое число – это вершина, являющаяся
ближайшим предком i-ой вершины с
таким же цветом. Если такого предка для вершины не существует, выведите -1.
Пример
входа |
Пример
выхода |
5 4 1 1 3 3 1 4 2 1 2 |
-1 -1 -1 1 3 |
графы –
поиск в глубину
Рассмотрим более
простой вариант задачи. Пусть все вершины дерева покрашены в один цвет. Объявим
стек, который изначально пуст. Запустим поиск в глубину из корня дерева. При
входе в вершину v кладем значение v
в стек, а при завершении обработки вершины v удаляем верхушку стека (это как раз будет вершина v). Когда поиск в глубину завершится,
стек окажется пустым.
Вопрос: что будет находиться на вершине стека при входе в
вершину v, до того как мы положим v в стек?
Теперь перейдем
к решению нашей задачи. Создадим c
стеков – по одному для каждого цвета (например, используем вектор стеков). Изначально
все стеки пусты. Запустим поиск в глубину из корня – вершины 1. Обработка
вершины v цвета color состоит из следующих шагов:
·
Если стек s[color]
не пуст, то на его вершине находится номер вершины, являющейся ближайшим
предком вершины v с таким же цветом,
как у v. Если стек пуст, то требуемой
вершины не существует, и ответом для вершины v будет -1.
·
Добавляем вершину v
в стек s[color].
·
Рекурсивно запускаем поиск в глубину со всех сыновей
вершины v.
·
Удаляем вершину v
из стека s[color].
Когда при поиске
в глубину мы находимся в вершине v, в
стеках хранится информация о цветах всех вершин, расположенных на единственном
пути от корня до v. То есть стек s[color] содержит номера вершин на пути от
корня до v, которые имеют цвет color. При этом вершины в стек заносятся
в порядке их посещения во время поиска в глубину.
Пример
Когда поиск в
глубину дойдет до вершины 5, из c = 4
стеков два будут пустыми (соответствующие цветам 3 и 4). Стек номер 1 (для первого
цвета) будет содержать вершину 1, стек номер 2 (для второго цвета) будет содержать
вершину 3. Вершина номер 5 имеет цвет 2, следовательно, ближайшим предком с таким
же цветом будет вершина, находящаяся на вершине стека 2. Таким предком для
вершины 5 будет вершина 3.
Реализация алгоритма
Объявим рабочие
массивы.
vector<int> col, res;
vector<vector<int> > g;
vector<stack<int> > s;
Функция dfs реализует поиск в глубину с вершины v.
void dfs(int
v)
{
Вершина v имеет цвет color.
int color =
col[v];
Номер ближайшего предка вершины v, имеющей цвет color, заносим в res[v].
if(s[color].empty())
res[v] = -1;
else
res[v] = s[color].top();
Заносим вершину v в стек номер color.
s[color].push(v);
Перебираем сыновей to вершины v и запускаем из
них рекурсивно поиск в глубину.
for (int to : g[v])
dfs(to);
Поиск в глубину выходит из вершины v. Извлекаем v из стека
номер color.
s[color].pop();
}
Основная часть программы. Читаем входные данные. Строим дерево.
scanf("%d %d", &n, &c);
g.resize(n + 1);
for(i = 2; i <= n; i++)
{
scanf("%d",&val);
g[val].push_back(i);
}
Читаем цвета вершин дерева.
col.resize(n + 1);
for(i = 1; i <= n; i++)
scanf("%d",&col[i]);
Запускаем поиск в глубину из вершины 1.
s.resize(c + 1);
res.resize(n + 1);
dfs(1);
Выводим ответ.
for(i = 1; i <= n; i++)
printf("%d
",res[i]);
printf("\n");
Python реализация
import sys
sys.setrecursionlimit(1000000)
def dfs(v):
color = col[v]
if not s[color]:
res[v] = -1
else:
res[v] = s[color][-1]
s[color].append(v)
for to in g[v]:
dfs(to)
s[color].pop()
n, c = map(int, input().split())
lst = list(map(int, input().split()))
g = [[] for _ in
range(n + 1)]
for i in range(2, n + 1):
val = lst[i - 2]
g[val].append(i)
col = [0] * (n + 1)
col[1:] = list(map(int, input().split()))
s = [[] for _ in
range(c + 1)]
res = [0] * (n + 1)
dfs(1)
print(*res[1:])