传送
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给定一棵n个点的树,问其中有多少条长度为偶数的路径。路径的长度为经过的边的条数。x到y与y到x被视为同一条路径。路径的起点与终点不能相同。
输入描述:
第一行一个数n表示点的个数; 接下来n-1行,每行两个整数x,y表示边; 保证输入数据形成一棵树; 1<=n<=100000
输出描述:
一行一个整数表示答案。
示例1
输入
3
1 2
1 3
输出
1
题解:
求长度为偶数的路径
偶数层的点到偶数层的点长度是偶数
奇数层到奇数层的点的路径长度也是偶数
奇数层的点到偶数层的点路径长度就算奇数
所以需要统计多少个奇数层多少点偶数层多少点
我们发现如果层数奇偶性一样,路径长度就是偶数
为什么呢?引用邓老师的讲解
我们可以考虑先让两个点里深度深的那个往上走,走到和另外一个点一样的高度,这个显然是偶数步完成的,之后两个点一起往上走直到汇合,走到步数是一样的,所以最终加起来也是偶数。
然后我们会用到数组dp[][]
dp[i][0/1]表示以i为根的子树,与根节点i的距离
因为距离长度只有偶数奇数两种情况,所以我们把偶数设为0,奇数设为1,这样好统计
u是v的父亲,
也就是一个来自v的子树的点,到u点的路径会比到v的路径长度 长1
这样我们有:
dp[u][0]+=dp[v][1]
以u为根的子树,与u的距离长度为偶数的情况一个本身,另一个来自dp[v][i].因为以v为根节点,与v的距离为奇数,那到u的距离就要加1,也就是偶数
dp[u][1]+=dp[v][0]
同理
sum + = dp [ u ] [ 0 ] * dp [ v ] [ 1 ] + dp [ u] [ 1 ] * dp [ v ] [ 0 ]
已有dp[u][0]条以u为端点长度为偶数的路径,与dp[v][1]条以v为端点长度为奇数的路径合并可以得到 dp [ u ] [ 0 ] * dp [ v ] [ 1 ] 条长度为偶数的路径
同理dp[u][i]*dp[v][0]也是一样
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=1e5+2;
using namespace std;
ll dp[maxn][3];
ll sum=0;
vector<int> edge[maxn];
void dfs(int u,int fa)
{
dp[u][0]=1;
for (int v : edge[u])
{
if(v==fa)continue;
dfs(v,u);
sum+=dp[u][0]*dp[v][1]+dp[u][1]*dp[v][0];
dp[u][0]+=dp[v][1];
dp[u][1]+=dp[v][0];
}
}
int main()
{
int n;
scanf("%d",&n);
int a,b;
for(int i=1;i<n;i++)
{
cin>>a>>b;
edge[a].push_back(b);
edge[b].push_back(a);
}
dfs(1,0);
cout<<sum;
}