首先树上路径计数一类的问题肯定可以上点分,但是有做法可以做到严格 。
考虑对于树上的一个点 ,在其子树点集 中的点 ()满足 ,则显然 只能和 中除了 以外的结点做贡献。于是考虑从根节点 开始对树做 dfs。对于当前结点 ,枚举儿子结点 并把当前 dfs 的结点移动到 。显然此时 不会和 以上所有颜色同样为 的结点产生贡献,因此此时记录 出现的颜色次数为 ,dfs 完之后再回溯即可。时间复杂度确实为 。
const int N = 1000100;
const int mod = 998244353;
vector<int> adj[N];
int a[N], buc[N], n, s;
void dfs(int u, int fa) {
int now = buc[a[u]];
s += now;
for (auto &v : adj[u])
if (v != fa) {
buc[a[u]] = 1;
dfs(v, u);
}
buc[a[u]] = now + 1;
}
signed main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i) adj[i].clear(), buc[i] = 0;
for (int i = 1; i < n; ++i) {
int x, y;
cin >> x >> y;
adj[x].eb(y), adj[y].eb(x);
}
s = 0;
dfs(1, 0);
cout << s << '\n';
}
}
喜欢的话,留下你的评论吧~