題目鏈接
題目解法
考慮對各個顏色建立滿足如下性質的圖 :
若顏色 形成的虛樹內存在顏色 ,連邊 。
若能夠得到 ,則運行 Tarjan 算法,找到出度爲零的所有強連通分量,取最優即可。
在樹上倍增優化建圖,可以得到具有同樣性質的圖。
時間複雜度 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXLOG = 20;
const int MAXP = 5e6 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int n, k, tot, depth[MAXN], timer, dfn[MAXN];
int point[MAXN][MAXLOG], father[MAXN][MAXLOG];
vector <int> t[MAXN], p[MAXN], a[MAXP];
namespace Tarjan {
int scc, belong[MAXP];
int timer, dfn[MAXP], low[MAXP];
int top, Stack[MAXP];
bool instack[MAXP];
void tarjan(int pos) {
dfn[pos] = low[pos] = ++timer;
instack[pos] = true;
Stack[++top] = pos;
for (unsigned i = 0; i < a[pos].size(); i++)
if (dfn[a[pos][i]] == 0) {
tarjan(a[pos][i]);
low[pos] = min(low[pos], low[a[pos][i]]);
} else if (instack[a[pos][i]]) low[pos] = min(low[pos], dfn[a[pos][i]]);
if (low[pos] == dfn[pos]) {
int tmp = Stack[top--];
instack[tmp] = false;
belong[tmp] = ++scc;
while (tmp != pos) {
tmp = Stack[top--];
instack[tmp] = false;
belong[tmp] = scc;
}
}
}
int work() {
static int cnt[MAXP];
static bool outd[MAXP];
for (int i = 1; i <= tot; i++)
if (dfn[i] == 0) tarjan(i);
for (int i = 1; i <= tot; i++)
for (auto x : a[i]) if (belong[x] != belong[i]) outd[belong[i]] = true;
for (int i = 1; i <= k; i++)
cnt[belong[i]]++;
int ans = k;
for (int i = 1; i <= scc; i++)
if (!outd[i]) chkmin(ans, cnt[i] - 1);
return ans;
}
}
int lca(int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
for (int i = MAXLOG - 1; i >= 0; i--)
if (depth[father[x][i]] >= depth[y]) x = father[x][i];
if (x == y) return x;
for (int i = MAXLOG - 1; i >= 0; i--)
if (father[x][i] != father[y][i]) {
x = father[x][i];
y = father[y][i];
}
return father[x][0];
}
void dfs(int pos, int fa) {
dfn[pos] = ++timer;
father[pos][0] = fa;
point[pos][0] = ++tot;
depth[pos] = depth[fa] + 1;
for (int i = 1; (1 << i) <= depth[pos]; i++) {
father[pos][i] = father[father[pos][i - 1]][i - 1];
point[pos][i] = ++tot;
a[tot].push_back(point[pos][i - 1]);
a[tot].push_back(point[father[pos][i - 1]][i - 1]);
}
for (auto x : t[pos])
if (x != fa) dfs(x, pos);
}
void addedge(int from, int x, int y) {
int z = lca(x, y);
for (int i = MAXLOG - 1; i >= 0; i--) {
if (depth[father[x][i]] >= depth[z]) {
a[from].push_back(point[x][i]);
x = father[x][i];
}
if (depth[father[y][i]] >= depth[z]) {
a[from].push_back(point[y][i]);
y = father[y][i];
}
}
a[from].push_back(point[z][0]);
}
int main() {
read(n), read(k), tot = k;
for (int i = 1; i <= n - 1; i++) {
int x, y; read(x), read(y);
t[x].push_back(y);
t[y].push_back(x);
}
dfs(1, 0);
for (int i = 1; i <= n; i++) {
int x; read(x);
p[x].push_back(i);
a[point[i][0]].push_back(x);
}
for (int i = 1; i <= k; i++) {
sort(p[i].begin(), p[i].end(), [&] (int x, int y) {return dfn[x] < dfn[y]; });
if (p[i].size()) {
p[i].push_back(p[i][0]);
for (unsigned j = 1; j < p[i].size(); j++)
addedge(i, p[i][j - 1], p[i][j]);
}
}
cout << Tarjan :: work() << endl;
return 0;
}