想清楚它不是DP而是贪心就好做了
首先, 我们称子树刚好包含所有某一颜色的点为临界点, 那我们要优先选择深度越深的临界点越好
用另一种方式来说, 在dfs的过程中, 第一次发现有一个点恰好为临界点,那么就选择这个点为分界线新增一个答案, 很容易想清楚, 选择越深的肯定更优, 让其它点的有更多分块的机会
这道题也有两种做法, 一种是找到每个颜色的临界点, 排序一遍再染色一遍即可
另一个方法是用dsu on tree, 不需要找lca, 每次找到满足条件的时候就ans++, 暴力求解即可
这里给出第一种方法的代码
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
#define fi first
#define se second
#define mp make_pair
#define sz(v) ((int)(v).size())
#define debug(a) cout << #a << " = " << a << endl;
typedef long long ll;
typedef pair <int, int> P;
vector < int > edge[N];
const ll MOD = 1e9 + 7;
int n, m;
int a[N], Size[N], dep[N], fa[N], hs[N], tot;
int minn[N], maxn[N], dfn;
void dfs(int u, int f, int d) {
dep[u] = d; fa[u] = f; Size[u] = 1; dfn++;
if (minn[a[u]] > n)
minn[a[u]] = u;
maxn[a[u]] = u;
for (int i = 0; i < sz(edge[u]); i++) {
int v = edge[u][i];
if (v == fa[u]) continue;
dfs(v, u, d + 1);
if (Size[v] > Size[hs[u]]) hs[u] = v;
Size[u] += Size[v];
}
}
int top[N];
void dfs2(int u, int T) {
top[u] = T;
if (!hs[u]) return ;
dfs2(hs[u], T);
for (int i = 0; i < sz(edge[u]); i++){
int v = edge[u][i];
if (hs[u] == v || v == fa[u]) continue;
dfs2(v, v);
}
}
inline int Lca(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] > dep[v] ? v : u;
}
struct node {
int a, b, c;
inline bool operator < (const node & o) const {
return a > o.a;
}
} v[N];
int col[N];
bool vis[N];
void add(int u) {
col[a[u]] = true; vis[u] = true;
for (int i = 0; i < sz(edge[u]); i++) {
int v = edge[u][i];
if (v == fa[u] || vis[v]) continue;
add(v);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
for (int Case = 1; Case <= T; Case++) {
memset(minn, 0x3f, sizeof(minn));
memset(maxn, 0xff, sizeof(maxn));
cin >> n; tot = 0;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
edge[u].push_back(v);
edge[v].push_back(u);
}
dfs(1, 0, 0);
dfs2(1, 1);
for (int i = 1; i <= n; i++)
if (minn[i] <= n && maxn[i] > 0) {
int l = Lca(minn[i], maxn[i]);
v[++tot] = {dep[l], l, i};
}
sort(v + 1, v + tot + 1);
int ans = 0;
for (int i = 1; i <= tot; i++) {
if (col[v[i].c]) continue;
add(v[i].b); ans++;
}
for (int i = 1; i <= n; i++)
vis[i] = false, col[i] = false, hs[i] = 0, edge[i].clear();
cout << "Case " << Case << ": " << ans << endl;
}
return 0;
}
联系客服