Використаємо систему неперетинних множин. Спочатку кожну вершину занесемо в окрему множину. Переберемо ребра в порядку спадання їхніх ваг, для кожного ребра запустимо функцію Union(u, v). Вона об'єднає множини, в яких знаходяться вершини та .
Розглянемо поточне ребро дерева з вагою . Нехай воно об'єднує множини з розмірами size[u] та size[v]. Усі ребра в цих двох множинах мають вагу не меншу, ніж . Ребро входить у size[u] \cdot size[v] різних шляхів. Оскільки вага мінімальна, то відстані цих шляхів дорівнюють . Тобто внесок цих шляхів у суму довжин усіх відстаней становить w \cdot size[u] \cdot size[v].
Приклад
Розглянемо перший тест.
Граф містить три шляхи:
1 → 2 (відстань );
1 → 3 (відстань );
2 → 1 → 3 (відстань );
Сума відстаней між усіма парами вершин дорівнює 1 + 3 + 1 = 5.
Розглянемо другий тест.
Кожну вершину віднесемо до окремої множини.
Перебираємо ребра в порядку спадання ваги. Першим буде ребро . Виконуємо Union(1, 3). Відстань має size[1] \cdot size[3] = 1 \cdot 1 = 1 шлях (з в ).
Наступним буде ребро . Виконуємо Union(4, 5). Відстань має size[4] \cdot size[5] = 1 \cdot 1 = 1 шлях (з в ).
Наступним буде ребро . Виконуємо Union(2, 4). Відстань має size[2] \cdot size[4] = 1 \cdot 2 = 2 шляхи (з в і з в ).
Наступним буде ребро . Виконуємо Union(1, 4). Відстань має size[1] \cdot size[4] = 2 \cdot 3 = 6 шляхів (2 → 4 → 1, 4 → 1, 5 → 4 → 1, 2 → 4 → 1 → 3, 4 → 1 → 3, 5 → 4 → 1 → 3).
Шукана сума відстаней дорівнює 7 + 5 + 6 + 12 = 30.
Реалізація алгоритму
Оголосимо масиви, використовувані системою неперетинних множин.
struct Edge
{
int u, v, cost;
} temp;
vector<Edge> e;
vector<int> parent, ssize;Функція — компаратор cmpGreater сортує ребра за спаданням ваги.
int cmpGreater(Edge a, Edge b)
{
return a.cost > b.cost;
}Функція Repr повертає представника множини, в якій знаходиться вершина .
int Repr(int v)
{
if (v == parent[v]) return v;
return parent[v] = Repr(parent[v]);
}Функція Union об'єднує множини з елементами та . Реалізуємо евристику з розмірами множин.
void Union(int x, int y)
{
x = Repr(x); y = Repr(y);
if (x == y) return;
if (ssize[x] < ssize[y]) swap(x, y);
parent[y] = x;
ssize[x] += ssize[y];
}Основна частина програми. Читаємо кількість вершин в графі.
scanf("%d", &n);Ініціалізуємо масиви.
parent.resize(n + 1);
ssize.resize(n + 1);
for (i = 0; i <= n; i++)
{
parent[i] = i;
ssize[i] = 1;
}Читаємо ребра дерева. Зберігаємо їх в масиві .
for (i = 0; i < n - 1; i++)
{
scanf("%d %d %d", &temp.u, &temp.v, &temp.cost);
e.push_back(temp);
}Сортуємо ребра за спаданням ваг.
sort(e.begin(), e.end(), cmpGreater);В змінній підраховуємо суму відстаней між усіма парами вершин.
res = 0;Перебираємо ребра. Для кожного ребра вагою запускаємо функцію Union(u, v). В додаємо вклад усіх шляхів з відстанню .
for (i = 0; i < e.size(); i++)
{
res += 1LL * e[i].cost * ssize[Repr(e[i].u)] * ssize[Repr(e[i].v)];
Union(e[i].u, e[i].v);
}Виводимо відповідь.
printf("%lld\n", res);Python реалізація
Оголосимо клас , що описує ребро графа.
class Edge:
def __init__(self, u, v, cost):
self.u = u
self.v = v
self.cost = costФункція — компаратор cmpGreater сортує ребра за спаданням ваги.
def cmpGreater(a, b):
return a.cost > b.costФункція Repr повертає представника множини, в якій знаходиться вершина .
def Repr(v):
if v == parent[v]: return v
parent[v] = Repr(parent[v])
return parent[v]Функція Union об'єднує множини з елементами та . Реалізуємо евристику з розмірами множин.
def Union(x, y):
x = Repr(x)
y = Repr(y)
if x == y: return
if ssize[x] < ssize[y]:
x, y = y, x
parent[y] = x
ssize[x] += ssize[y]Основна частина програми. Читаємо кількість вершин в графі.
n = int(input().strip())Ініціалізуємо масиви.
parent = list(range(n + 1))
ssize = [1] * (n + 1)
e = []Читаємо ребра дерева. Зберігаємо їх у списку .
for _ in range(n - 1):
u, v, cost = map(int, input().split())
e.append(Edge(u, v, cost))Сортуємо ребра за спаданням ваг.
e.sort(key=lambda x: x.cost, reverse=True)В змінній підраховуємо суму відстаней між усіма парами вершин.
res = 0Перебираємо ребра. Для кожного ребра вагою запускаємо функцію Union(u, v). В додаємо вклад усіх шляхів з відстанню .
for edge in e:
res += edge.cost * ssize[Repr(edge.u)] * ssize[Repr(edge.v)]
Union(edge.u, edge.v)Виводимо відповідь.
print(res)