Ağac#2923

Ağac (Həll təhlili)

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");