序列算法-前缀和
一般的前缀和是对于数组的求和,即对数组的某一子数组进行求和,即Sum(i,j) == sum[i] - sum[j-1]
。
不仅如此前缀和还能用于任何含可逆运算的运算符包括异或xor
。
上述的子数组和的问题属于数组固定,大量访问的问题优化。
下面给出一个大量做区间加的情况:
给定一个序列a 有很多次操作,每个操作形如:A l r k 将a_[l,r]每个值加上k. 最后输出整个数组。复杂度要求O(n).
如果用传统方法,n次操作当lr区间长度达到n就成了O(n^2)了,自然不符合题意。
所以这里利用到了差分数组(描述序列元素的递推关系,以更快的方式体现序列元素的增减)。
对于如下序列:
5 4 7 2 4 3 1
经过如下计算:
得到差分数组:
5 -1 3 -5 2 -1 -2
然后再求差分数组的前缀和可以发现:
sum[i] == line[i]
并且给差分数组的一个元素+x后,其后面直到-x的元素(不包括),他们的前缀和均+i(即line元素+i),这就回归到了我们的题目要求上。
由查分数组的这些性质可以解决更多类似这种问题。
所以代码如下:
int n;//数组元素个数
int l,r,k;
int a[100005];
int change[100005];
int sum[100005];
void fun(int m)//m次操作
{
memset(change,0,sizeof(change));
memset(sum,0,sizeof(sum));
for(int i = 1;i <= n;i++) //求差
{
cin >> a[i];
change[i] += a[i] - a[i-1];
}
for(int i = 0;i < m;i++) //对差分元素进行加减运算
{
cin>>l>>r>>k;
change[l] += k;
change[r + 1] -= k;
}
for(int i = 1;i <= n;i++) //求差分数组前缀和并输出
{
sum[i] = sum[i-1] + change[i];
cout<<sum[i]<<" ";
}
}