update 1009睡觉前,更新了多维前缀和和树上前缀和
前缀和
前缀和
定义
前缀和是一种重要的预处理,能大大降低查询的时间复杂度。
可以简单理解为“数列的前(n)项的和”。
实现非常简单。
开两个数组(A[n],B[n])。
然后把(A)数组前(n)项累加放入(B)数组。
代码实现:
B[i]=A[i]+B[i-1];
二维/多维前缀和
基于容斥原理
多维前缀和的普通求解方法几乎基于容斥原理(扫雷原理)
比如我们有这样一个矩阵(alpha),可以视为二维数组(借用(OI~ ~WIKI)的数据)。
1 2 4 3
5 1 2 4
6 3 5 9
我们同样定义(sum)
那么所求出的二维前缀和矩阵长成:
1 3 7 10
6 9 15 22
12 18 29 45
为了防止有的人(未来回看的我自己)看不懂上面的(sum)式子。
我随便举几个栗子
7=1+2+4
18=1+2+5+1+6+3
这样应该就挺好理解了……吧。
那么显而易见的第一个问题就是通过递推求(sum)的过程。
(sum_{i,j}=sum{i-1,j}+sum_{i,j-1}-sum_{i-1,j-1}+a_{i,j})
如图所示,显然要减去中间重复的一部分。
第二个问题就是如何应用,求((x1,y1)-(x2,y2))子矩阵的和。
那么,根据类似的思考过程,很容易得到答案(sum_{x2,y2}-sum_{x1-1,y2}-sum_{x2,y1-1}+sum_{x1-1,y1-1})。
基于(DP)思想
基于容斥原理计算的方法优点在于形式简单,不需要特别记忆,但当维数升高时,其复杂度较高。
还有一种通过(DP)来计算高维前缀和的方法。
设高维空间(U)共有(N)维,需要对(f[cdot])求高维前缀和(sum[cdot])。
令(sum[i][state])表示同(state)后(D-i)维相同的所有点对于(state)点高维前缀和的贡献。
有定义可知(sum[0][state]=f[state]),以及(sum[state]=sum [D][state])。
其递推关系为(sum[i][state]=sum[i-1][state]+sum[i][state']),其中(state')为第(i)维恰好比(state)少1的点。
该方法的时间复杂度为(O(D imes |U|)),其中(|U|)为高维空间(U)的大小。
伪代码实现:
for state
sum[state]=f[state];
for(i=0;i<=D;i++)
for 以字典序从小到大枚举state
sum[state]+=sum[state'];
树上前缀和
设(sum_i)表示结点(i)到根结点的权值总和。
- 若是边权,(x),(y)路径上的和为(sum_x)+(sum_y)-(2sum_lca)。
- 若是点权,(x),(y)路径上的和为(sum_x)+(sum_y)-(sum_lac)-(sum_{f_{a_{lca}}})。
(LCA)的求法参见最近公共祖先