介绍

给定一个序列 \(a\) ,其相邻两项之差构成另一个序列 \(s\),则称 \(s\) 为差分数组。
下图是一个简单的例子:image
差分数组主要适用于区间修改。如上表中的例子,我们进行该操作:将下标区间为\([1,4]\)内的元素都加上3。暴力方法是进行遍历,给每一个元素都加上该数值,但是这样的话时间消耗很大,但对于差分数组而言,只有在其下标区间的端点处才会有数值大小的改变,而其余地方是不变的,在上述区间内操作后结果如下:image
事实上,当对一个区间进行增减某个值的时候,其差分数组只有对应区间的左右端点值会变化,而且左右端点的值变化相反。如对于区间\([a,b]\)中加上一个数 \(x\), 则有\(s[a] += x, s[b + 1] -=x\).
由于上述性质的存在,显然差分数组的作用就是求对一个区间多次修改之后的数组。我们有:$$a[i]=a[i-1]+s[i]$$
除此之外,序列 \(a\) 中的某元素 \(a[i]\) 可以用差分数组 \(s\) 中的元素表示:\(a[i]=a[i]-a[i-1]+a[i-1]-a[i-2]+...+a[1]-a[0]\) , 显然后面那一串的和为差分数组 \(s\) 的前 \(i\) 项和 \(\sum_{k=1}^is[k]\). 此外,如果我们只想快速得到少量位置的现值的话,应该用树状数组维护差分而不是前缀和。

例题

Color the ball
image
代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100002;
int ball[N];
int diff[N];
int main()
{
	ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  int n;
  int x, y;
  while(cin >> n && n)
  {
    memset(ball, 0, sizeof(ball));
    memset(diff, 0, sizeof(diff));
    for(int i = 0; i < n; i++)
    {
      cin >> x >> y;
      diff[x]++;
      diff[y + 1]--;
    }  
    for(int i = 1; i <= n; i++)
    {
      ball[i] = ball[i - 1] + diff[i];
    }
    for(int i = 1; i < n; i++)
    {
      cout << ball[i] << " ";
    }
    cout << ball[n] << endl;
  }
  
  return 0;
}
posted on 2023-04-02 20:57  sc01  阅读(34)  评论(0编辑  收藏  举报