首先前缀和
前缀和就是一种预处理,用空间来换取时间,降低时间复杂度,它可以非常灵活的面对关于区间的询问。简单点说就是提前计算好前缀和数组sum[i],在后面计算的时候直接使用
原数组a[i] 前缀和数组sum[i]
sum[1] = a[1]
sum[2] = a[1] + a[2] = sum[1] + a[2]
sum[3] = a[1] + a[2] + a[3] = sum[2] + a[3]
sum[4] = a[1] + a[2] + a[3] + a[4] = sum[3] + a[4]
.
.
sum[n] = a[1] + a[2] + …+ a[n] = sum[n-1] + a[n]
for(int i=1;i<=n;i++)
{
cin >> a[i];
sum[i] = sum[i-1] + a[i];
}
对于前缀和,最常见的题目就是T次询问,每次给定一个区间[L,R],求区间内序列的和
当然直接暴力跑也不是不可以,但是在数据范围比较大的时候,可能会超时,但是使用前缀和就可以把O(n*m)的复杂度降为O(n)
这样区间[L,R]的和就是sum[r] - sum[l-1]
然后差分
定义一个数组c为差分数组,那么
c[1] = a[1] - a[0]
c[2] = a[2] - a[1]
c[3] = a[3] - a[2]
.
.
c[n] = a[n] - a[n-1]
我们可以看出差分数组其实就是原数组相邻两项之间的差
例如这样一个序列a
0 0 0 0 0
我们要在区间[2,4]中给每个数加上1
那么序列a将要变成
0 1 1 1 0
差分数组c就会变成
0 1 0 0 -1
我们可以发现对原数组的某个区间 [l,r] 值进行改变就相当于对差分数组的元素l,r+1进行改变,即c[l]++,c[r+1]–,这样就把对原数组的区间修改变成了对差分数组的单点修改
for(int i=1;i<=n;i++) cin >> a[i];
while(T--)
{
int l,r;
cin >> l >> r;
c[l]++,c[r+1]--;
}
我们再看差分数组,这次定义一个数组sum记录差分数组的前缀和
a[0] = 0
c[i] = a[i] - a[i-1]
sum[1] = c[1] = a[1]
sum[2] = c[1] + c[2] = a[2]
sum[3] = c[1] + c[2] + c[3] = a[3]
.
.
sum[n] = c[1] + c[2] + c[3] +…+c[n] = a[n]
我们发现差分数组的前缀和就是原数组,这样就通过前缀和得到了原序列
关于差分最基础的题就是有N个气球排成一排,从左到右依次编号为1,2,3…N.每次给定2个整数a b(a <= b),从气球a开始到气球b依次给每个气球涂一次颜色。求N次以后每个气球被涂过几次色
这个题看明白之后就是求差分的前缀和
int a[maxn],b[maxn];
int n;
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
int l,r;
cin >> l >> r;
b[l]++,b[r+1]--;
}
for(int i=1;i<=n;i++)
a[i] = a[i-1]+b[i];
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
return 0;
}