-
Notifications
You must be signed in to change notification settings - Fork 496
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
3a36af1
46ad346
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,124 @@ int main() { | |
</CPPSection> | ||
</LanguageSection> | ||
|
||
<IncompleteSection> | ||
## 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. | ||
|
||
<LanguageSection> | ||
<CPPSection> | ||
|
||
```cpp | ||
#include <bits/stdc++.h> | ||
using namespace std; | ||
|
||
// BeginCodeSnip{Segment Tree} | ||
template <class T> class SumSegmentTree { | ||
Vaishnav-K787 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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; | ||
} | ||
}; | ||
// EndCodeSnip | ||
|
||
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. 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. i agree 👍 i would prefer a lambda function, but it's up to you |
||
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; } | ||
} | ||
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; | ||
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. why is this initialized here |
||
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>()); | ||
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. make these vector declarations on separate lines |
||
|
||
vector<int> sizes(n, 0), heavy_index(n, -1), path_index(n, -1), depth(n, 0), | ||
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. same thing w/ declaring stuff on deparate lines also, vectors autofill to 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<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()); | ||
} | ||
|
||
</IncompleteSection> | ||
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 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 still throws a compilation error on usaco's website. 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. oh lol, then change it back |
||
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'; } | ||
} | ||
``` | ||
|
||
</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.
if this is copy-paste from the module, you should add (from the module) in the code snip title