diff --git a/solutions/gold/usaco-696.mdx b/solutions/gold/usaco-696.mdx
index 2b3f0e0388..15dfd3a07a 100644
--- a/solutions/gold/usaco-696.mdx
+++ b/solutions/gold/usaco-696.mdx
@@ -3,6 +3,7 @@ id: usaco-696
source: USACO Platinum 2017 January
title: Promotion Counting
author: Benjamin Qi, Timothy Gao, William Yuan
+contributors: Vaishnav Krishnan
---
[Official Editorial (Java)](http://www.usaco.org/current/data/sol_promote_platinum_jan17.html)
@@ -306,10 +307,124 @@ int main() {
-
+## Solution 3: HLD
-Add Centroid Decomp/HLD Solution
+**Time Complexity:** $\mathcal{O}(N\log ^2N)$
+
+Sort the cows from largest to smallest proficiency. For each cow, perform a path update that adds one to all cows from itself to the president.
+
+
+
+
+```cpp
+#include
+using namespace std;
+
+// BeginCodeSnip{Segment Tree}
+template class SumSegmentTree {
+ private:
+ T DEFAULT = 0;
+
+ vector segtree;
+ int len;
+
+ public:
+ SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {}
+
+ void set(int ind, T val) {
+ ind += len;
+ segtree[ind] = val;
+ for (; ind > 1; ind /= 2) {
+ segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1];
+ }
+ }
+
+ T range_sum(int start, int end) {
+ T sum = DEFAULT;
+ for (start += len, end += len; start < end; start /= 2, end /= 2) {
+ if (start % 2 == 1) { sum += segtree[start++]; }
+ if (end % 2 == 1) { sum += segtree[--end]; }
+ }
+ return sum;
+ }
+};
+// EndCodeSnip
+
+void dfs_hld(vector> &edges, vector> &heavy_paths,
+ vector &depth, vector &sizes, int start) {
+ int heavy_child = -1;
+ ++sizes[start];
+ for (int i : edges[start]) {
+ depth[i] = depth[start] + 1;
+ dfs_hld(edges, heavy_paths, depth, sizes, i);
+ sizes[start] += sizes[i];
+ if (heavy_child == -1 || sizes[heavy_child] < sizes[i]) { heavy_child = i; }
+ }
+ if (heavy_child != -1) {
+ swap(heavy_paths[start], heavy_paths[heavy_child]);
+ heavy_paths[start].push_back(heavy_child);
+ }
+}
+
+int main() {
+ freopen("promote.in", "r", stdin);
+ freopen("promote.out", "w", stdout);
+ int n, current_value;
+ cin >> n;
+ vector> cow_proficiency(n);
+ for (int i = 0; i < n; ++i) {
+ cin >> cow_proficiency[i].first;
+ cow_proficiency[i].second = i;
+ }
+ vector edges(n, vector()), heavy_paths(n, vector());
+
+ vector sizes(n, 0), heavy_index(n, -1), path_index(n, -1), depth(n, 0),
+ parents(n, -1), ans(n, 0), cur_ans(n, 0);
+
+ for (int i = 1; i < n; ++i) {
+ cin >> parents[i];
+ edges[--parents[i]].push_back(i);
+ }
-Sort nodes from largest to smallest value, do path updates from itself the root.
+ dfs_hld(edges, heavy_paths, depth, sizes, 0);
+ vector segtrees(n, SumSegmentTree(0));
+ for (int i = 0; i < n; ++i) {
+ reverse(heavy_paths[i].begin(), heavy_paths[i].end());
+ for (int j = 0; j < (int)heavy_paths[i].size(); ++j) {
+ heavy_index[heavy_paths[i][j]] = i;
+ path_index[heavy_paths[i][j]] = j;
+ }
+ segtrees[i] = SumSegmentTree((int)heavy_paths[i].size());
+ }
-
+ sort(cow_proficiency.begin(), cow_proficiency.end(), greater>());
+ for (auto &[proficiency, cow] : cow_proficiency) {
+ if (heavy_index[cow] != -1) {
+ ans[cow] = segtrees[heavy_index[cow]].range_sum(0, path_index[cow] + 1);
+ } else {
+ ans[cow] = cur_ans[cow];
+ }
+ cow = parents[cow];
+ while (cow >= 0) {
+ if (heavy_index[cow] != -1) {
+ current_value = segtrees[heavy_index[cow]].range_sum(0, 1);
+ segtrees[heavy_index[cow]].set(0, current_value + 1);
+ if (path_index[cow] + 1 < (int)heavy_paths[heavy_index[cow]].size()) {
+ current_value = segtrees[heavy_index[cow]].range_sum(
+ path_index[cow] + 1, path_index[cow] + 2);
+ segtrees[heavy_index[cow]].set(path_index[cow] + 1,
+ --current_value);
+ }
+ cow = parents[heavy_paths[heavy_index[cow]][0]];
+ } else {
+ ++cur_ans[cow];
+ cow = parents[cow];
+ }
+ }
+ }
+ for (int i = 0; i < n; ++i) { cout << ans[i] << '\n'; }
+}
+```
+
+
+