#include <bits/stdc++.h>
using namespace std;
// A custom hash to reduce collisions and the overhead of unordered_map.
struct custom_hash {
static uint64_t splitmix64(uint64_t x) {
x += 0x9e3779b97f4a7c15ULL;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;
x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;
return x ^ (x >> 31);
}
size_t operator()(uint64_t x) const {
static const uint64_t random_constant = chrono::steady_clock::now().time_since_epoch().count();
return splitmix64(x + random_constant);
}
};
//––– Typedefs and macros –––
typedef int ll;
typedef pair<ll, ll> pi;
#define pb push_back
#define mp make_pair
ll const blk = 1000;
ll n, k, label = 0;
ll color[100005], par[100005], in[100005], out[100005], cnt[100005], dep[100005], big[100005];
vector<ll> adj[100005], nodelist[100005];
// Instead of an unordered_set for each color’s depths, we use a vector.
vector<ll> deplist[100005];
// We now define our maps with the custom hash.
unordered_map<ll, ll, custom_hash>
dp[100005],
dp2[100005],
dp3[100005],
dp4[100005],
dp5[100005],
colMap[100005]; // this stores, per color, the overall counts by depth
// Answer stored as (res, -swaps) so that max() works lex–order.
pi ans = mp(-1000000000, -1000000000);
//––– precomp1: Euler Tour + collect depths for each color –––
void precomp1(ll x = 0) {
in[x] = ++label;
for (ll u : adj[x]) {
dep[u] = dep[x] + 1;
precomp1(u);
}
out[x] = label;
// Instead of deplist[color[x]].insert(...), we simply push_back.
deplist[color[x]].pb(dep[x]);
}
//––– precomp2: Build dp and record “col” frequencies –––
void precomp2(ll x = 0) {
// Instead of a separate “col” map, we store counts in colMap indexed by color.
colMap[color[x]][dep[x]]++;
for (ll u : adj[x]) {
precomp2(u);
// Small-to–large merging: always merge the smaller map into the larger.
if (dp[x].size() < dp[u].size()) swap(dp[x], dp[u]);
for (auto &p : dp[u])
dp[x][p.first] += p.second;
dp[u].clear();
}
dp[x][dep[x]]++;
// Only build dp2 if this color is “small” (here we check by big[color])
if (!big[color[x]]) {
for (ll d : deplist[color[x]])
dp2[x][d] += dp[x][d];
}
}
//––– dfs: process “big” colors –––
void dfs(ll x, ll c, ll yes = 1) {
for (ll u : adj[x]) {
dfs(u, c, yes & (color[x] != c));
if (dp4[x].size() < dp4[u].size()) swap(dp4[u], dp4[x]);
for (auto &p : dp4[u])
dp4[x][p.first] += p.second;
if (dp5[x].size() < dp5[u].size()) swap(dp5[u], dp5[x]);
for (auto &p : dp5[u])
dp5[x][p.first] += p.second;
dp4[u].clear();
dp5[u].clear();
}
if (yes && color[x] == c) {
ll res = 0, res2 = 0;
// Iterate only over unique depths for this color.
for (ll d : deplist[c]) {
if (d <= dep[x]) continue;
ll take = min(dp4[x][d], colMap[c][d]);
res += take;
res2 += max(0, take - dp5[x][d]);
}
ans = max(ans, mp(res, -res2));
}
dp4[x][dep[x]]++;
if (c == color[x])
dp5[x][dep[x]]++;
}
//––– solve: process “small” colors –––
void solve(ll c) {
int sz = nodelist[c].size();
for (int i = 0; i < sz; i++) {
for (int j = i + 1; j < sz; j++) {
ll x = nodelist[c][i], y = nodelist[c][j];
if (in[x] > in[y]) swap(x, y);
if (in[x] <= in[y] && in[y] <= out[x])
dp3[x][dep[y]]++;
}
}
for (int i = 0; i < sz; i++) {
ll x = nodelist[c][i];
ll res = 0, res2 = 0;
for (ll d : deplist[c]) {
if (d <= dep[x]) continue;
ll take = min(dp2[x][d], colMap[c][d]);
res += take;
res2 += max(0, take - dp3[x][d]);
}
dp2[x].clear();
dp3[x].clear();
ans = max(ans, mp(res, -res2));
}
}
//––– main –––
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> n >> k;
for (ll i = 0; i < n; i++){
cin >> color[i];
cnt[color[i]]++;
nodelist[color[i]].pb(i);
}
for (ll i = 0; i < k; i++){
if (cnt[i] > blk)
big[i] = 1;
}
for (ll i = 1; i < n; i++){
cin >> par[i];
adj[par[i]].pb(i);
}
precomp1();
// For each color, sort and unique the list of depths
for (ll i = 0; i < k; i++){
sort(deplist[i].begin(), deplist[i].end());
deplist[i].erase(unique(deplist[i].begin(), deplist[i].end()), deplist[i].end());
}
precomp2();
for (ll i = 0; i < k; i++){
if (big[i]) {
// Clear temporary maps before processing a new “big” color.
for (ll j = 0; j < n; j++){
dp5[j].clear();
dp4[j].clear();
}
dfs(0, i, 1);
} else {
solve(i);
}
}
cout << ans.first + 1 << " " << -ans.second << "\n";
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |