蒟蒻复习之—–前缀和和差分
#前缀和#
##1.一维前缀和##
对于数组A[],前缀和SUM[i]表示的就是A[1]+A[2]+…+A[i]。
int init() {
for(int i = 1; i <= n; i++) sum[i] = sum[i-1] + a[i];
}
int get(int l, int r) {
return sum[r] - sum[l-1];
}
##2.二维前缀和##
对于二维数组,前缀和SUM[i][k]表示的是所有A[i’][k’](1< = i’<=i,i <= k’<=k)的和。
int init() {
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j];
}
}
}
int get(int x1, int y1, int x2, int y2) {
return sum[x1][y1] - sum[x1][y2 - 1] - sum[x2 - 1][y1] + sum[x2 - 1][y2 - 1];
}
##3.%k时的优化##
(p - q)% k= 0 ==> p % k = q % k
统计q % k 和 p % k 相等的数
详细见T1
#差分#
##1.一维差分##
我们对[L,R]区间进行加num操作,在C[L]处加上num,在C[R+1]处减去num
差分可以 O(1)处理 O(n)求和
void init(int l,int r,int num) {
dis[l] += num, dis[r + 1] -= num;
}
int get() {
for(int i = 1; i <= n; i++) {
val[i] = val[i-1] + dis[i];
}
}
##2.二维差分##
//这才是最大的坑,发现自己不会打二维的差分T_T
其实也挺简单,和二维前缀和一样
void init(int x1, int y1, int x2, int y2, int num) {
sum[x1][y1] += num;
sum[x1][y2 + 1] -= num;
sum[x2 + 1][y1] -= num;
sum[x2 + 1][y2 + 1] += num;
}
void get() {
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
sum[i][j] += sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1];
}
}
}
##3.树上差分##
###(1)点差分###
对 u 到 v 的路径上的点 +num
用来求 - 已知路径求树上所有节点被路径覆盖次数
int init(int u, int v, int num) {
dis[u] += num;
dis[v] += num;
dis[lca(u,v)] -= num;
dis[f[lca(u,v)]] -= num;
}
###(2)边差分###
对 u 到 v 的路径上的边 +num
用来求 - 已知路径求被所有路径覆盖的边
dis[i] 表示以i节点为儿子的边
int init(int u, int v, int num) {
dis[u] += num;
dis[v] += num;
dis[lca(u,v)] -= 2 *num;
}
最后dfs遍历一遍
void dfs(int x) {
for(int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if(v != f[x][0]) { //f[x][0] 为倍增数组
dfs(v);
dis[x] += dis[v];
}
}
}

浙公网安备 33010602011771号