补题链接:Here
题意总结:寻找有多少条两个点之间偶数路径
看完题,很容易想到在树型中,同一层的节点必然是偶数路径到达,还有就是每隔两层的节点一样可以到达,所以我就理所应当的写了如下代码
using ll = long long;
const int N = 1e5 + 10;
vector<int> e[N], deg(N);
int dep[N], Siz[N];
int Mdep = -1;
void dfs(int u, int fa) {
for (int v : e[u]) {
if (v == fa) continue;
dep[v] = dep[u] + 1;
Mdep = max(Mdep, dep[v]);
Siz[dep[v]]++;
dfs(v, u);
}
}
void solve() {
int n;
cin >> n;
for (int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
deg[v]++;
}
int root = 0;
for (int i = 1; i <= n && !root; ++i)
if (!deg[i]) root = i;
dep[root] = 1, Siz[1] = 1;
dfs(root, -1);
ll ans = 0;
for (int i = 1; i <= Mdep; ++i) {
ans += Siz[dep[i]] * (Siz[dep[i]] - 1) / 2;
for (int j = i + 2; j <= Mdep; j += 2)
ans += Siz[dep[i]] * Siz[dep[j]];
}
cout << ans << "
";
}
然后就GG了,通过率为 (0\%)
WA之后重新理解一下题意,发现这个就是一道枚举起点和终点的 (LCA) ,然后将他们两两组合即可。
具体的,设 (f[i][0/1])表示以 (i) 为根的子树中,与根节点 (i) 的距离为偶数(0)奇数(1)的点的数量。
转移方程:(f[u][x] += f[v][x ⊗ 1])
然后考虑统计答案,以 (u) 为 (LCA) 的两个节点,肯定不能在(u) 的同一个儿子里,所以转移的过程中, (f[u][0/1]) 表示已经当前已经计算过得儿子造成的贡献,对于一个新的儿子 (v), (ans += f[u][0]·f[v][1] + f[u][1]·f[v][0])
AC 代码:
using ll = long long;
const int N = 1e5 + 10;
vector<int> e[N];
ll ans = 0, f[N][2];
void dfs(int u, int fa) {
f[u][0] = 1;
for (int v : e[u]) {
if (v == fa) continue;
dfs(v, u);
ans += f[v][1] * f[u][0];
ans += f[v][0] * f[u][1];
f[u][0] += f[v][1];
f[u][1] += f[v][0];
}
}
void solve() {
int n;
cin >> n;
for (int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
e[u].push_back(v), e[v].push_back(u);
}
dfs(1, 0);
cout << ans << '
';
}
顺便一句,以前牛客比赛的数据好水....,连下面这种代码都能过 (60\%)
using ll = long long;
ll dp[100010], ans, odd, even, n;
void solve() {
cin >> n;
for (int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
dp[v] = dp[u] + 1;
ans += (dp[v] & 1 ? even++ : ++odd);
}
cout << ans << "
";
}