蒟蒻复习之—–前缀和和差分

#前缀和#
##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];
		}
	}
}
posted @ 2017-11-08 14:35  Taunt  阅读(109)  评论(0)    收藏  举报