前缀和
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\times |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\)的求法参见最近公共祖先