Submission #217169

#TimeUsernameProblemLanguageResultExecution timeMemory
217169rama_pangCapital City (JOI20_capital_city)C++14
100 / 100
898 ms38524 KiB
#include <bits/stdc++.h>
using namespace std;

class CapitalCity {
 
 private:

  int N, K;
  vector<int> color;

  vector<vector<int>> adj;
  vector<vector<int>> color_adj;
  
  class Visited {

   private:

    int visited_mark = 1;
    vector<int> visited;

   public:

    Visited() {}

    void Initialize(int n) {
      visited.resize(n);
    }

    void Clear() {
      visited_mark++;
    }

    bool IsIt(int n) {
      return n == -1 || visited[n] == visited_mark;
    }

    void Mark(int n) {
      if (n != -1) visited[n] = visited_mark;
    }

  };

  Visited visited, reachable;

  vector<int> parent;
  vector<int> sz;
  vector<bool> deleted;

  void Dfs(int n, bool r = true) {
    if (r) {
      assert(!deleted[n]);
      parent[n] = -1;
      reachable.Clear();
      reachable.Mark(n);
    }

    sz[n] = 1;
    for (auto &i : adj[n]) if (i != parent[n] && !deleted[i]) {
      reachable.Mark(i);
      parent[i] = n;
      Dfs(i, false);
      sz[n] += sz[i];
    }
  }

  int SolveColor(int root, int k) {
    assert(color[root] == k);
    Dfs(root);

    queue<int> q;
    visited.Clear();

    for (auto &c : color_adj[k]) {
      if (reachable.IsIt(c)) {
        q.emplace(c);
        visited.Mark(c);
      } else {
        return -1;
      }
    }

    int ans = 0;

    while (!q.empty()) {
      int u = q.front();
      q.pop();
      if (!visited.IsIt(parent[u])) {
        ans++;
        for (auto &c : color_adj[color[parent[u]]]) {
          if (reachable.IsIt(c)) {
            q.emplace(c);
            visited.Mark(c);
          } else {
            return -1;
          }
        }
      }
    }

    return ans;
  }

  int Centroid(int n) {
    Dfs(n);
    int cur = n;
    while (true) {
      pair<int, int> mx = {-1, -1};
      for (auto &i : adj[cur]) if (i != parent[cur] && !deleted[i]) {
        mx = max(mx, {sz[i], i});
      }
      if (mx.first * 2 <= sz[n]) {
        return cur;
      }
      cur = mx.second;
    }
  }

  int CentroidDecomposition() {
    set<int> can;
    for (int i = 0; i < N; i++) {
      can.emplace(i);
    }

    auto Delete = [&](int x) {
      for (auto &c : color_adj[x]) {
        can.erase(c);
        deleted[c] = true;
      }
    };
    
    int ans = N - 1;

    while (!can.empty()) {
      int u = *begin(can);
      u = Centroid(u);
      int current = SolveColor(u, color[u]);
      if (current != -1) ans = min(ans, current);
      Delete(color[u]);
    }

    return ans;
  }

  void Init() {
    visited.Initialize(N);
    reachable.Initialize(N);

    parent.resize(N);
    sz.resize(N);
    deleted.resize(N);
  }

 public:

  void Read() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin >> N >> K;

    adj.resize(N);
    color.resize(N);
    color_adj.resize(K);

    for (int i = 0; i + 1 < N; i++) {
      int u, v;
      cin >> u >> v;
      u--, v--;
      adj[u].emplace_back(v);
      adj[v].emplace_back(u);
    }

    for (int i = 0; i < N; i++) {
      cin >> color[i];
      color[i]--;
      color_adj[color[i]].emplace_back(i);
    }
  }

  int Solve() {
    Init();
    return CentroidDecomposition();
  }

};

int main() {
  CapitalCity Solver;
  Solver.Read();
  cout << Solver.Solve() << "\n";
  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...