Submission #1274227

#TimeUsernameProblemLanguageResultExecution timeMemory
1274227trufanov.pTeam Coding (EGOI24_teamcoding)C++20
100 / 100
1637 ms47856 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <random>
#include <map>
#include <unordered_map>
#include <cmath>

using namespace std;

#pragma GCC optimize("O3")
#pragma GCC optimization("Ofast,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

typedef long long ll;

const int SIZE = 1e5 + 5;

int n, k;
int C;
int c[SIZE];
int cnt[SIZE];
vector<int> light, heavy;
vector<int> light_sets[SIZE];
vector<int> gr[SIZE];

int tin[SIZE], tout[SIZE];
int timer = 0;
vector<int> atDepth[SIZE];
int d[SIZE];
int max_depth[SIZE];

unordered_map<int, vector<int>> colOnDepth[SIZE];

int maxSubTree = 0, minSwaps = 0;

int dfs_precalc(int v, int cur_d = 0) {
    tin[v] = timer++;
    atDepth[cur_d].push_back(tin[v]);
    colOnDepth[c[v]][cur_d].push_back(tin[v]);
    d[v] = cur_d;
    max_depth[v] = cur_d;
    for (int u : gr[v]) {
        max_depth[v] = max(max_depth[v], dfs_precalc(u, cur_d + 1));
    }
    tout[v] = timer++;
    return max_depth[v];
}

int countSubDepth(int v, int d) {
    return lower_bound(atDepth[d].begin(), atDepth[d].end(), tout[v]) - lower_bound(atDepth[d].begin(), atDepth[d].end(), tin[v]);
}

int countSubColDepth(int v, int d) {
    return lower_bound(colOnDepth[c[v]][d].begin(), colOnDepth[c[v]][d].end(), tout[v]) - lower_bound(colOnDepth[c[v]][d].begin(), colOnDepth[c[v]][d].end(), tin[v]);
}

void solve_light(int c) {
    for (int v : light_sets[c]) {
        int cur_ans = 1, cur_swaps = 0;
        for (const auto& p : colOnDepth[c]) {
            if (p.first <= d[v]) {
                continue;
            }
            int poss = min(countSubDepth(v, p.first), (int)p.second.size());
            cur_ans += poss;
            cur_swaps += poss - countSubColDepth(v, p.first);
        }
        if (cur_ans > maxSubTree || (cur_ans == maxSubTree && cur_swaps < minSwaps)) {
            maxSubTree = cur_ans;
            minSwaps = cur_swaps;
        }
    }
}

void solve_heavy(int v) {
    int cur_ans = 1, cur_swaps = 0;
    for (int dep = d[v] + 1; dep <= max_depth[v]; ++dep) {
        int poss = min(countSubDepth(v, dep), (int)colOnDepth[c[v]][dep].size());
        cur_ans += poss;
        cur_swaps += poss - countSubColDepth(v, dep);
    }
    if (cur_ans > maxSubTree || (cur_ans == maxSubTree && cur_swaps < minSwaps)) {
        maxSubTree = cur_ans;
        minSwaps = cur_swaps;
    }
}

void dfs_heavy(int v, int col) {
    if (c[v] == col) {
        solve_heavy(v);
        return;
    }
    for (int u : gr[v]) {
        dfs_heavy(u, col);
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> k;
    C = (int)sqrt(n);
    for (int i = 0; i < n; ++i) {
        cin >> c[i];
        cnt[c[i]]++;
    }
    for (int i = 0; i < k; ++i) {
        if (cnt[i] != 0) {
            if (cnt[i] < C) {
                light.push_back(i);
            } else {
                heavy.push_back(i);
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        if (cnt[c[i]] < C) {
            light_sets[c[i]].push_back(i);
        }
    }
    for (int i = 1; i < n; ++i) {
        int p;
        cin >> p;
        gr[p].push_back(i);
    }
    dfs_precalc(0);
    for (int c : light) {
        solve_light(c);
    }
    for (int c : heavy) {
        dfs_heavy(0, c);
    }
    cout << maxSubTree << ' ' << minSwaps << '\n';
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...