-
Notifications
You must be signed in to change notification settings - Fork 495
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HLD solution for Promotion Counting(Platinum) #4886
base: master
Are you sure you want to change the base?
Changes from all commits
65d39d4
61a667e
fa296a4
69b7b1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,122 @@ int main() { | |
</CPPSection> | ||
</LanguageSection> | ||
|
||
<IncompleteSection> | ||
## Solution 3: HLD | ||
|
||
Add Centroid Decomp/HLD Solution | ||
**Time Complexity:** $\mathcal{O}(N\log ^2N)$ | ||
|
||
Sort the nodes from largest to smallest value, do path updates from each node to the root. | ||
|
||
<LanguageSection> | ||
<CPPSection> | ||
|
||
```cpp | ||
#include <bits/stdc++.h> | ||
using namespace std; | ||
|
||
template <class T> class SumSegmentTree { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. put this in a codesnip |
||
private: | ||
T DEFAULT = 0; | ||
|
||
vector<T> 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; | ||
} | ||
}; | ||
|
||
void dfs_hld(vector<vector<int>> &edges, vector<vector<int>> &heavy_paths, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok i personally find this to be kind of ugly, ngl IMO there's two ways to clean it up
I would say don't change it yet, but be aware that you might be asked to later. |
||
vector<int> &depth, vector<int> &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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just in general put braces around blocks of code even if it's one statement |
||
} | ||
if (heavy_child != -1) { | ||
swap(heavy_paths[start], heavy_paths[heavy_child]); | ||
heavy_paths[start].push_back(heavy_child); | ||
} | ||
} | ||
|
||
Sort nodes from largest to smallest value, do path updates from itself the root. | ||
int main() { | ||
freopen("promote.in", "r", stdin); | ||
freopen("promote.out", "w", stdout); | ||
int N, current_value; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. very, very, very minor but preferably use |
||
cin >> N; | ||
vector<pair<int, int>> cow_proficiency(N); | ||
for (int i = 0; i < N; ++i) { | ||
cin >> cow_proficiency[i].first; | ||
cow_proficiency[i].second = i; | ||
} | ||
vector edges(N, vector<int>()), heavy_paths(N, vector<int>()); | ||
|
||
vector<int> sizes(N, 0), heavy_index(N, -1), path_index(N, -1), depth(N, 0), | ||
parents(N, -1), ans(N, 0), cur_ans(N, 0); | ||
|
||
</IncompleteSection> | ||
for (int i = 1; i < N; ++i) { | ||
cin >> parents[i]; | ||
edges[--parents[i]].push_back(i); | ||
} | ||
|
||
dfs_hld(edges, heavy_paths, depth, sizes, 0); | ||
vector segtrees(N, SumSegmentTree<int>(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>((int)heavy_paths[i].size()); | ||
} | ||
|
||
sort(cow_proficiency.begin(), cow_proficiency.end(), greater<pair<int, int>>()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it works locally but throws a compile error on usaco There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. most guide code is written to be submitted in C++ 17 I'm pretty sure cuz like, with C++ there's literally no disadvantage with going with a higher version (I'm pretty sure) if ur curious why, it's cuz of class template argument deduction |
||
for (auto &p : cow_proficiency) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider using a structured binding e.g. |
||
if (heavy_index[p.second] != -1) { | ||
ans[p.second] = | ||
segtrees[heavy_index[p.second]].range_sum(0, path_index[p.second] + 1); | ||
} else ans[p.second] = cur_ans[p.second]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. braces |
||
p.second = parents[p.second]; | ||
while (p.second >= 0) { | ||
if (heavy_index[p.second] != -1) { | ||
current_value = segtrees[heavy_index[p.second]].range_sum(0, 1); | ||
segtrees[heavy_index[p.second]].set(0, current_value + 1); | ||
if (path_index[p.second] + 1 < | ||
(int)heavy_paths[heavy_index[p.second]].size()) { | ||
current_value = segtrees[heavy_index[p.second]].range_sum( | ||
path_index[p.second] + 1, path_index[p.second] + 2); | ||
segtrees[heavy_index[p.second]].set(path_index[p.second] + 1, | ||
--current_value); | ||
} | ||
p.second = parents[heavy_paths[heavy_index[p.second]][0]]; | ||
} else { | ||
++cur_ans[p.second]; | ||
p.second = parents[p.second]; | ||
} | ||
} | ||
} | ||
for (int i = 0; i < N; ++i) { cout << ans[i] << '\n'; } | ||
} | ||
``` | ||
|
||
</CPPSection> | ||
</LanguageSection> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i get what you mean but like, maybe make the wording a bit more specific
like: "Sort the nodes in descending order of proficiency. When adding in each node, we do a path update from the root to this node." (except be specific with what type of path update we do)