Submission #1244891

#TimeUsernameProblemLanguageResultExecution timeMemory
1244891quannnguyen2009Capital City (JOI20_capital_city)C++20
11 / 100
2145 ms589824 KiB
#include <bits/stdc++.h>
using namespace std;

// naive SCC + Tarjan solution without HLD/segment tree optimization
// vertices are colors 1..k
// graph edges: u->v if color u depends on color v along tree paths

static const int MAXN = 200000;
static const int LOG = 18;

int n, k;
vector<int> tree[MAXN+1];
int color[MAXN+1];
int parent[LOG][MAXN+1], depth[MAXN+1];

// DFS to fill parent[0] and depth
void dfs(int u, int p) {
    parent[0][u] = p;
    for (int v : tree[u]) {
        if (v == p) continue;
        depth[v] = depth[u] + 1;
        dfs(v, u);
    }
}

// Binary-lifted LCA
int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    int diff = depth[u] - depth[v];
    for (int i = 0; i < LOG; i++)
        if (diff & (1 << i)) u = parent[i][u];
    if (u == v) return u;
    for (int i = LOG-1; i >= 0; i--) {
        if (parent[i][u] != parent[i][v]) {
            u = parent[i][u];
            v = parent[i][v];
        }
    }
    return parent[0][u];
}

// dependency graph on colors
vector<vector<int>> G2;

// Tarjan's SCC data
vector<int> dfn, low, comp;
vector<bool> onstack;
stack<int> st;
int timer = 0, compCnt = 0;

void tarjan(int u) {
    dfn[u] = low[u] = ++timer;
    st.push(u);
    onstack[u] = true;
    for (int v : G2[u]) {
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (onstack[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (low[u] == dfn[u]) {
        compCnt++;
        while (true) {
            int v = st.top(); st.pop();
            onstack[v] = false;
            comp[v] = compCnt;
            if (v == u) break;
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n >> k;
    for (int i = 1; i < n; i++) {
        int u, v; cin >> u >> v;
        tree[u].push_back(v);
        tree[v].push_back(u);
    }
    for (int i = 1; i <= n; i++) {
        cin >> color[i];
    }

    // build depth & parent table
    depth[1] = 0;
    dfs(1, 0);
    for (int i = 1; i < LOG; i++) {
        for (int u = 1; u <= n; u++) {
            parent[i][u] = parent[i-1][ parent[i-1][u] ];
        }
    }

    // group nodes by color
    vector<vector<int>> byColor(k+1);
    for (int u = 1; u <= n; u++) byColor[color[u]].push_back(u);

    // init dependency graph for colors 1..k
    G2.assign(k+1, {});

    // build naive edges
    for (int c = 1; c <= k; c++) {
        if (byColor[c].empty()) continue;
        // compute LCA of all nodes of this color
        int u = byColor[c][0];
        for (int v : byColor[c]) u = lca(u, v);
        // walk each node up to u
        for (int v : byColor[c]) {
            int x = v;
            while (x != u) {
                int p = parent[0][x];
                G2[c].push_back(color[p]);
                x = p;
            }
        }
    }

    // prepare Tarjan
    dfn.assign(k+1, 0);
    low.assign(k+1, 0);
    comp.assign(k+1, 0);
    onstack.assign(k+1, false);

    // run Tarjan on each color node
    for (int i = 1; i <= k; i++) if (!dfn[i]) tarjan(i);

    // count sizes of components
    vector<int> compSize(compCnt+1, 0);
    for (int i = 1; i <= k; i++) compSize[ comp[i] ]++;

    // build condensed DAG and mark bad components
    vector<vector<int>> dag(compCnt+1);
    vector<bool> bad(compCnt+1, false);
    for (int u = 1; u <= k; u++) {
        for (int v : G2[u]) {
            if (comp[u] != comp[v]) {
                dag[ comp[u] ].push_back(comp[v]);
                if (compSize[ comp[v] ] > 0) bad[ comp[u] ] = true;
            }
        }
    }

    // propagate bad flag
    vector<bool> visited(compCnt+1, false);
    function<void(int)> dfs2 = [&](int u) {
        if (visited[u]) return;
        visited[u] = true;
        for (int v : dag[u]) {
            dfs2(v);
            if (bad[v]) bad[u] = true;
        }
    };
    for (int i = 1; i <= compCnt; i++) dfs2(i);

    // compute answer
    int answer = k - 1;
    for (int i = 1; i <= compCnt; i++) {
        if (!bad[i] && compSize[i] > 0) {
            answer = min(answer, compSize[i] - 1);
        }
    }
    cout << answer;
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...