由题可知这是一棵树,因此求每一条边经过的次数可以通过树上差分解决。而现在只有部分(有向)边需要花费,因此就需要找到一种能够记录单向花费的信息。考虑到一条边连接的两个点因在树上而深度不同,所以可以分为叶子指向父节点与父节点指向叶子两种边。形象化地,第一种可以称为上行边,第二种称为下行边。
首先通过树上差分,将信息分别储存在上行边的起点与下行边的中点。
for (int i = 1;i <= k;++i)
{
int lca = getLCA (a[i],a[i - 1]);
++up[a[i - 1]];++down[a[i]];//up 加的位置为起点,down 加的位置为终点
--up[lca];--down[lca];
}
然后通过一次 dfs
和差分数组还原每一条边经过的次数。最后统计答案,对于一条 v→uv \to uv→u 需要花费的边,若是上行边,那么通过的次数记录在 vvv 上,否则是 uuu 上。设某条边经过了 xxx 次,则总花费为 1+2+⋯+2x−1=2x−11 + 2 + \cdots + 2^{x - 1} = 2^x - 11+2+⋯+2x−1=2x−1,所以直接预处理 222 的幂次即可。
总代码如下:
#include <iostream>
#include <cstdio>