Ağacın kökündən başlayaraq dərinlik üzrə ağacı gəzin. Hər bir zirvəsi üçün s_i çoxluğunu saxlayacağıq ki, burada kökü olan alt ağacda olan bütün zirvələrin rəngləri toplanır.
Əgər zirvəsi gəzinti prosesində zirvəsinin oğludursa, onda s_j çoxluğu s_i içərisinə daxil edilməlidir.
Kökü zirvəsində olan alt ağacda fərqli rənglərin sayı s_i çoxluğunun gücünə (ölçüsünə) bərabərdir.
Nümunə
Hər bir zirvənin solunda onun rəngi, sağında isə bu zirvənin kökü olduğu alt ağacda olan rənglərin çoxluğu göstərilir.
Alqoritmin həyata keçirilməsi
color[i] massivində zirvəsinin rengi saxlanılır. çoxluğunda isə kökü olan alt ağacda qarşılaşan rənglər toplanacaq.
Əyri ağac qrafın qonşuluq siyahısı şəklində təqdim olunub, . massivində kökü olan alt ağacdakı müxtəlif rənglərin sayı saxlanılır.
#define MAX 1000010
int color[MAX], res[MAX];
set<int> s[MAX];
vector<vector<int> > g;dfs funksiyası zirvəsindən başlayaraq dərinlik üzrə ağacı gəzir.
void dfs(int v)
{İlk olaraq çoxluğuna zirvəsinin öz rəngini əlavə edirik.
s[v].insert(color[v]);Ağacın kənarlarını (v, to) araşdırırıq.
for (int to : g[v])
{
dfs(to);Hər bir (v, to) kənarı üçün çoxluğunu çoxluğuna əlavə edirik. Əgər çoxluğunun ölçüsü çoxluğunun ölçüsündən kiçikdirsə, onları yerləri ilə dəyişdiririk. Daha sonra kiçik çoxluğunun məzmununu çoxluğuna əlavə edirik.
if (s[v].size() < s[to].size()) s[v].swap(s[to]);
s[v].insert(s[to].begin(), s[to].end());çoxluğunu təmizləyirik — bizə daha lazım deyil.
s[to].clear();
}Bundan sonra -də alt ağacdakı fərqli rənglərin sayını yazırıq, yəni çoxluğunun ölçüsü.
res[v] = s[v].size();
}Proqramın əsas hissəsi. Giriş məlumatlarını oxuyuruq.
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;
}Ağacın kökündən - nömrəli zirvədən dərinlik axtarışına başlayırıq.
dfs(0);Cavabı çıxardırıq.
for(i = 1; i <= n; i++)
printf("%d ",res[i]);
printf("\n");