📅  最后修改于: 2023-12-03 14:56:53.167000             🧑  作者: Mango
本文介绍如何计算二叉树路径中奇数位 AND 的数量。具体地,给定一棵二叉树和一个整数 $Q$,对于每个节点 $u$,需要计算从 $u$ 开始的路径中,长度为奇数的子路径(即 $u \to v_1 \to v_2 \to \dots \to v_k$,$k$ 为奇数)的 AND 值为 $Q$ 的数量。
我们可以使用树上差分的方法求解。具体地,我们可以定义一个长度为 $n$ 的数组 $a$,其中 $a_i$ 表示根到节点 $i$ 的路径中,长度为奇数的子路径的 AND 值。然后,我们会维护一个长度为 $n$ 的数组 $d$,其中 $d_i$ 表示节点 $i$ 的子树中以其为起点,长度为奇数,且以其为中点的子路径的 AND 值为 $Q$ 的数量。这里的“以其为中点”指的是:如果路径长度为 $k$($k$ 为奇数),则路径必须含有一个点 $i$,使得 $i$ 到 $u$ 的距离等于 $(k-1)/2$,其中 $u$ 是路径的起点(也就是它到 $u$ 的距离为 $(k+1)/2$)。
接下来,我们考虑如何计算 $d$ 数组。我们可以使用类似前缀和的思想,从根节点开始遍历树,然后对于每个节点 $u$,我们令 $s$ 表示从根节点到 $u$ 的路径中的长度为奇数的子路径的 AND 值。然后,我们遍历 $u$ 的所有子节点 $v$,然后对于每个子节点 $v$,我们令 $t$ 表示从 $v$ 出发的、长度为奇数、以 $u$ 为中点的路径的个数,其中的路径必须包含 $u$ 和 $v$(如果 $u$ 不是路径中的中点,那么 $v$ 就是中点)。然后,我们令 $d_v=d_v+t$,$d_u=d_u+t$,$s=s & a_v$。其中,$&$ 表示按位与运算。这个过程可以通过树状数组或线段树实现,时间复杂度为 $O(n \log n)$。
最后,我们可以使用一个类似前缀和的过程来计算答案。具体地,我们从根节点开始遍历树,然后对于每个节点 $u$,我们令 $t$ 表示从 $u$ 开始的、长度为奇数的子路径,其 AND 值为 $Q$ 的数量。我们可以计算 $t$ 的值,然后令 $ans_u=ans_{\text{parent}(u)}+t$,其中 $\text{parent}(u)$ 表示节点 $u$ 的父节点。这个过程的时间复杂度为 $O(n)$。
下面是使用 Python 实现上述算法的代码片段(为了简化,这里没有包括树状数组或线段树的代码):
n,q=map(int,input().split())
a=[0]*n # a[i] 表示根到节点 i 的路径中,长度为奇数的子路径的 AND 值
d=[0]*n # d[i] 表示节点 i 的子树中,以其为起点,长度为奇数,以其为中点的子路径的 AND 值为 Q 的数量
# 计算 a 数组
def dfs1(x,fa):
for y in g[x]:
if y==fa:
continue
dfs1(y,x)
a[x]=a[x]&a[y]
a[x]=a[x]&v[x]
# 计算 d 数组
def dfs2(x,fa):
s=v[x]
for y in g[x]:
if y==fa:
continue
dfs2(y,x)
t=0 # 从 y 出发的、长度为奇数、以 x 为中点的路径的数量
for k in [1,-1]:
p=(k+a[y])&1
q=((k+s)&1)&p
t+=d[y][q]
d[y][a[x]&1]+=t
d[x][a[y]&1]+=t
s&=a[y]
d[x][a[x]&1]+=1
# 计算答案
def dfs3(x,fa):
t=0 # 从 x 开始、长度为奇数,AND 值为 Q 的子路径的数量
for k in [1,-1]:
p=(k+a[x])&1
q=((k+q)&1)&p
t+=d[x][q]
ans[x]=ans[fa]+t
for y in g[x]:
if y==fa:
continue
dfs3(y,x)
dfs1(0,-1)
dfs2(0,-1)
dfs3(0,-1)