2.8
Treepath
链接:https://ac.nowcoder.com/acm/problem/14248
题解:给一颗树,求无序的偶长度路径数量
对于每一个节点,考虑两种路径
1.当前节点到子节点的路径
只需要预处理出\(t[i]\)和\(k[i]\),分别表示当前节点到子节点的偶路径数和奇路径数(为了方便统计,包含自己,计算时减去就行了),每到一个节点将\(t[i]++\),并把子节点的奇路径数加到偶路径数,偶路径数加到奇路径数(因为长度为1,会改变奇偶),统计就不用说了。
2.不同子树的子节点经过当前节点的路径
不同子树的子节点经过当前节点的路径为偶只有两种情况:到当前节点的路径长度同奇或同偶。
所以每统计一个子树,就更新奇路径节点和偶路径节点的个数,按统计子树的每个奇节点和偶节点与前面子树分别匹配就完了。
时间复杂度:\(O(n)\)
Code
#include <bits/stdc++.h>
using namespace std;
#define R
typedef long long ll;
const int MAXN = 5e5 + 5;
int Last[MAXN],End[MAXN],Next[MAXN],cnt;
ll k[MAXN],t[MAXN];
void add(int x,int y)
{
End[++cnt] = y;Next[cnt] = Last[x];Last[x] = cnt;
}
void dfs1(int x,int fa)
{
t[x] = 1;
for(R int i = Last[x];i; i = Next[i])
{
int y = End[i];
if(y != fa)
{
dfs1(y,x);
k[x] += t[y];
t[x] += k[y];
}
}
}
ll ans;
void dfs2(int x,int fa)
{
int kk = 0,tt = 0;
ans += t[x] - 1;
for(R int i = Last[x];i; i = Next[i])
{
int y = End[i];
if(y != fa)
{
ans += k[y] * kk + t[y] * tt ;
kk += k[y];
tt += t[y];
dfs2(y,x);
}
}
}
int main()
{
int n;
scanf("%d", &n);
for(R int i = 1;i < n; i++)
{
int x,y;
scanf("%d %d", &x, &y);
add(x,y);
add(y,x);
}
dfs1(1,0);
dfs2(1,0);
printf("%lld", ans);
return 0;
}