题解 [校内模拟赛]路径颜色数
求 \(\sum_{i=1}^{n-1}\sum_{j=i+1}^n \text {colnum}(i, j)\)
清新题!!!
看到的时候觉得要主席树什么的黑科技,然而只需要一个 dfs。
首先将问题进行巧妙转化,变成对于没一条边 \(u \to v\),求链使得其靠 \(u\) (深度较浅)的那边没出现过颜色 \(c\)。这个转化自己想不到,但是告诉你了,想想好像就是这么回事。
然后链的一点肯定在 \(v\) 子树中,只要考虑另外一点有几个。可以用一个数组——就叫 twt
吧——在 dfs 的时候记录。
我们首先令 twt[i] = n
,然后在每次经过颜色为 \(c\) 的边的时候把 \(twt_c\) 变成 \(size_v\),这样,在往下走的时候上面能到这儿的满足条件的链树就是 \(twt_c - size_v\),那么考虑往上走了以后怎么办,为了防止重复,得把走出的这个子树里的给清了,那么只要在下去的时候记录一个 \(t\),回来的时候变成 \(t-size_v\) 即可!
代码。
#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
#define int long long
const int N = 500005;
int n, ans, size[N], twt[N];
std::vector<std::pair<int, int> > g[N];
void dfs(int u, int fa) {
size[u] = 1;
for (int i = 0; i < (int)g[u].size(); i++) {
int v = g[u][i].first;
if (v == fa) continue;
dfs(v, u);
size[u] += size[v];
}
}
void get(int u, int fa) {
for (int i = 0; i < (int)g[u].size(); i++) {
int v = g[u][i].first, col = g[u][i].second;
if (v == fa) continue;
ans += size[v] * (twt[col] - size[v]);
int t = twt[col];
twt[col] = size[v];
get(v, u);
twt[col] = t - size[v];
}
}
signed main() {
std::cin >> n;
for (int i = 1; i <= n; i++) twt[i] = n;
for (int i = 1, x, y, z; i < n; i++) {
std::cin >> x >> y >> z;
g[x].push_back(std::make_pair(y, z));
g[y].push_back(std::make_pair(x, z));
}
dfs(1, 0), get(1, 0);
std::cout << ans;
}