#include <bits/stdc++.h>
using namespace std;
constexpr int INF32 = 1e9;
struct Tree {
int n; // number of nodes
vector<vector<int>> g; // children
vector<int> lang; // language of each node
vector<int> tin, tout, eul, depth, sz, heavy;
int timer = 0, maxDepth = 0;
Tree(int N) : n(N), g(N), lang(N), tin(N), tout(N),
eul(N), depth(N), sz(N), heavy(N, -1) {}
void addEdge(int parent, int child) { g[parent].push_back(child); }
void dfs0(int u) { // sizes, depths and heavy-child
tin[u] = timer; eul[timer] = u; timer++;
sz[u] = 1;
int best = 0;
for (int v : g[u]) {
depth[v] = depth[u] + 1;
maxDepth = max(maxDepth, depth[v]);
dfs0(v);
sz[u] += sz[v];
if (sz[v] > best) best = sz[v], heavy[u] = v;
}
tout[u] = timer - 1;
}
};
/* ────────────────────────────────────────────────────────────────────────── */
/* helpers shared by the two phases */
struct CounterByDepth {
vector<vector<int>> byDepth; // tin-indices per depth (monotonically increasing)
explicit CounterByDepth(int maxD) : byDepth(maxD + 1) {}
void add(int d, int tin) { byDepth[d].push_back(tin); }
// number of nodes at depth d inside Euler interval [l,r]
int count(int d, int l, int r) const {
const auto &vec = byDepth[d];
return int(upper_bound(vec.begin(), vec.end(), r) -
lower_bound(vec.begin(), vec.end(), l));
}
};
/* ────────────────────────────────────────────────────────────────────────── */
/* global answer */
struct Best { long long team = -1; long long sw = INF32; };
inline void upd(Best &best, long long team, long long sw) {
if (team > best.team || (team == best.team && sw < best.sw))
best.team = team, best.sw = sw;
}
/* ────────────────────────────────────────────────────────────────────────── */
/* phase 1 : “rare” colours */
void solveRareColour(int c,
const vector<int>& nodes, // all nodes of colour c
const unordered_map<int,int>& cap, // cap[d] = #nodes of c at depth d
const vector<int>& tin,
const vector<int>& tout,
const CounterByDepth& counter,
const Tree& T,
Best& best)
{
vector<int> depthList; depthList.reserve(cap.size());
for (auto &kv : cap) depthList.push_back(kv.first);
for (int u : nodes) {
long long val = 0;
for (int d : depthList) {
int inside = counter.count(d, tin[u], tout[u]);
int limit = cap.at(d);
val += min(inside, limit);
}
// initial good employees of colour c in the subtree:
long long good = 0;
for (int w : nodes)
if (tin[w] >= tin[u] && tin[w] <= tout[u]) ++good;
upd(best, val, val - good);
}
}
/* ────────────────────────────────────────────────────────────────────────── */
/* phase 2 : “heavy” colours – one DSU-on-tree run per colour */
struct HeavySolver {
const Tree& T;
const vector<int>& cap; // cap[d] for current colour
Best& best;
int curColour;
vector<int> freq; // current freq at depth d
long long curSum = 0; // Σ min(freq[d],cap[d])
long long goodCnt = 0; // employees of colour c in current subtree
HeavySolver(const Tree& T_, const vector<int>& cap_, int colour, Best& b)
: T(T_), cap(cap_), best(b), curColour(colour),
freq(T_.maxDepth + 1, 0) {}
void add(int node) {
int d = T.depth[node];
int old = freq[d]++;
curSum += min(old+1, cap[d]) - min(old, cap[d]);
if (T.lang[node] == curColour) ++goodCnt;
}
void remove(int node) {
int d = T.depth[node];
int old = freq[d]--;
curSum += min(old-1, cap[d]) - min(old, cap[d]);
if (T.lang[node] == curColour) --goodCnt;
}
void addSubtree(int l, int r) { // inclusive Euler interval
for (int i = l; i <= r; ++i) add(T.eul[i]);
}
void remSubtree(int l, int r) {
for (int i = l; i <= r; ++i) remove(T.eul[i]);
}
void dfs(int u, bool keep) {
for (int v : T.g[u])
if (v != T.heavy[u]) dfs(v, false);
if (T.heavy[u] != -1) dfs(T.heavy[u], true);
for (int v : T.g[u])
if (v != T.heavy[u]) addSubtree(T.tin[v], T.tout[v]);
add(u);
if (T.lang[u] == curColour)
upd(best, curSum, curSum - goodCnt);
if (!keep) remSubtree(T.tin[u], T.tout[u]);
}
};
void solveHeavyColour(int colour,
const vector<int>& nodes,
const CounterByDepth& counter,
Tree& T,
Best& best)
{
vector<int> cap(T.maxDepth + 1, 0);
for (int v : nodes) ++cap[T.depth[v]];
HeavySolver S(T, cap, colour, best);
S.dfs(0, false);
}
/* ────────────────────────────────────────────────────────────────────────── */
/* main driver */
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, K;
if (!(cin >> N >> K)) return 0;
Tree T(N);
for (int i = 0; i < N; ++i) cin >> T.lang[i];
for (int v = 1, b; v < N; ++v) { // bosses
cin >> b;
T.addEdge(b, v);
}
T.dfs0(0); // preprocessing
/* depth lists for O(log N) counting */
CounterByDepth counter(T.maxDepth);
for (int v = 0; v < N; ++v)
counter.add(T.depth[v], T.tin[v]);
/* bucket nodes by colour */
vector<vector<int>> byColour(K);
for (int v = 0; v < N; ++v) byColour[T.lang[v]].push_back(v);
const int B = (int)std::sqrt(N) + 1; // threshold between rare / heavy
Best best; // final answer
/* phase 1 – rare colours */
for (int c = 0; c < K; ++c) {
int cnt = (int)byColour[c].size();
if (cnt == 0 || cnt >= B) continue;
unordered_map<int,int> cap;
for (int v : byColour[c]) ++cap[T.depth[v]];
solveRareColour(c, byColour[c], cap,
T.tin, T.tout, counter, T, best);
}
/* phase 2 – heavy colours */
for (int c = 0; c < K; ++c) {
int cnt = (int)byColour[c].size();
if (cnt < B) continue; // handled already
solveHeavyColour(c, byColour[c], counter, T, best);
}
cout << best.team << ' ' << best.sw << '\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... |