Виконуємо обхід дерева в глибину, починаючи з кореня. Для кожної вершини будемо зберігати множину s_i, у якій накопичуються кольори всіх вершин, що входять у піддерево з коренем в .
Якщо — син вершини в процесі обходу, то множина s_j повинна бути включена в s_i.
Кількість різних кольорів у піддереві з коренем у вершині дорівнює потужності (розміру) множини s_i.
Приклад
Ліворуч для кожної вершини вказано її колір, праворуч — множина кольорів, що містяться в піддереві з коренем у цій вершині.
Реалізація алгоритму
У масиві color[i] зберігається колір вершини . У множині будемо накопичувати кольори, що зустрічаються в піддереві з коренем у вершині .
Орієнтоване дерево представлено у вигляді списку суміжності графа . У масиві зберігається кількість різних кольорів у піддереві з коренем у вершині .
#define MAX 1000010
int color[MAX], res[MAX];
set<int> s[MAX];
vector<vector<int> > g;Функція dfs виконує обхід дерева в глибину, починаючи з вершини .
void dfs(int v)
{Спочатку у множину додаємо колір самої вершини .
s[v].insert(color[v]);Перебираємо ребра дерева (v, to).
for (int to : g[v])
{
dfs(to);Для кожного ребра (v, to) додаємо множину у . Якщо розмір множини менший за розмір множини , то міняємо їх місцями. Далі вміст меншої множини додаємо у множину .
if (s[v].size() < s[to].size()) s[v].swap(s[to]);
s[v].insert(s[to].begin(), s[to].end());Очищаємо множину — вона нам більше не знадобиться.
s[to].clear();
}Після цього у записуємо кількість різних кольорів у піддереві, тобто розмір множини .
res[v] = s[v].size();
}Основна частина програми. Читаємо вхідні дані.
scanf("%d",&n);
g.resize(n+1);
for(i = 1; i <= n; i++)
{
scanf("%d %d",&p,&c);
g[p].push_back(i);
color[i] = c;
}Запускаємо пошук в глибину з кореня дерева — вершини з номером .
dfs(0);Виводимо відповідь.
for(i = 1; i <= n; i++)
printf("%d ",res[i]);
printf("\n");