1.定义
对于已知有n个元素的离线数列d,我们可以建立记录它每项与前一项差值的差分数组f:显然,f[1]=d[1]-0=d[1];对于整数i∈[2,n],我们让f[i]=d[i]-d[i-1]。
2.应用
区间加减操作:O(1)
假如现在对数列中区间[L,R]上的数加上x,令f[L]+=x,f[R+1]-=x即可。
询问每一项的值:O(n)
求差分数组前缀和即可
数组前缀和:O(n)
第i项的前缀和即为数列前i项的和,那么推导可知
3.题目
leetcode5615 使数组互补的最少操作次数
class Solution {
public:
int minMoves(vector<int>& nums, int limit) {
int n = nums.size();
vector<int> delta(limit * 2 + 2);
for (int i = 0; i < n / 2; ++i) {
int lo = 1 + min(nums[i], nums[n - i - 1]);
int hi = limit + max(nums[i], nums[n - i - 1]);
int sum = nums[i] + nums[n - i - 1];
delta[lo]--;
delta[sum]--;
delta[sum + 1]++;
delta[hi + 1]++;
}
int now = n;
int ans = n;
for (int i = 2; i <= limit * 2; ++i) {
now += delta[i];
ans = min(ans, now);
}
return ans;
}
};
HDU1511 Color the ball
-N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
-Input:每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。当N = 0,输入结束。
-Output:每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
线段树或差分数组皆可
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int d[100010],a[100010],l,r;
int main(){
int n;
while(scanf("%d",&n),n)
{
memset(d,0,sizeof(d));
memset(a,0,sizeof(a));
for(int i=1;i<=n;++i){
scanf("%d%d",&l,&r);
d[l]+=1;
d[r+1]-=1;
}
for(int i=1;i<=n;++i) a[i]=a[i-1]+d[i];
for(int i=1;i<n;++i) printf("%d ",a[i]);
printf("%d\n",a[n]);
}
return 0;
}
[洛谷P3948]数据结构
最开始的数组每个元素都是0
给出n,opt ,min,max,mod 在int范围内
A: L ,R ,X 表示把[l,R] 这个区间加上X(数组的从L到R的每个元素都加上X)
Q : L ,R 表示询问[L,R] 这个区间中元素T满足 min<=(T∗i %mod)<=max 的 T这样的数的个数(i是数组下标)(元素的值*数组下标%mod在min到max范围内)
待补。。
codeforces_1110_E
http://codeforces.com/contest/1110/problem/E
待补。。