差分
差分构造方式
原数组A,差分数组B,数组范围【1,n】
B[1] = A[1] - A[0] = A[1]
B[i] = A[i] - A[i-1]
差分特点
B数组的前缀和 <> A数组的元素值
SUM{B[1~i ]} = A[i]
A 数组的区间加 <> B数组的单点修改
A[L]~A[R] 均加上c
等价于B【L] += c, B[R+1] -= c
题目描述
有 nn 个人买东西同一个商品,第 ii 个人认为合理的价格区间 [l_i,r_i]表示如果价格低于 l嫌便宜,如果价格高于 r 嫌贵。
请你设计商品的价格,使在满足尽可能多的人认为价格合理的条件下,商品价格最高。具体来说,你需要输出最终商品的定价与认为价格合理的人数。
输入描述
第一行输入一个整数 n(1<= n <=10^6)
接下来 n 行,第 i 行输入两个数 l_i, r_il (1 <= l_i <= r_i <=10^6)表示第 ii个人认为的价格合理的区间。
输出描述
输出一行两个整数,以一个空格分割,分别表示最终商品的定价与认为价格合理的人数。
输入样例
5
1 3
2 4
2 3
3 4
4 5
输出样例
3 4
解题思路
差分,构造差分数组b[i],当有一个合理区间,l r,则在数组a上从a[l]到a[r]每一个都加一,即b[l]+1,b[r+1]+1,最终统计值最大得a[i],从最大值中找最大的i
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int b[N] = {0};
int a[N] = {0};
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int n;
cin>>n;
for(int i = 0;i < n;i++)
{
int l,r;
cin>>l>>r;
b[l]++;
b[r+1]--;
}
int num = 0;
int price;
for(int i=1;i <= n;i++)
{
a[i] = a[i-1] + b[i];
if(a[i] >= num)
{
num = a[i];
price = i;
}
}
cout<<price<<" "<<num<<endl;
return 0;
}
关于差分的思考
将原数组看作是前缀和数组,通过辅助数组(差分数组)b,对数组b进行前缀,还原原数组。
因为只需要修改差分数组的单点的值,就能对前缀中的许多值产生影响:
比如,b:1 2 3 4 5 ,原数组(前缀和)1 3 6 10 15
修改后 b:2 2 3 4 5 ,原数组从第一个数开始,每一个数的值都加1,
如果只需要将第1到4个数的值加1,对差分数组的第五个数减1,来抵消影响,
即 2 2 3 4 4 原数组变为:2 4 7 11 15
二维差分
原先二维数组最为二位前缀和,差分数公式推导为
p [i] [j] = a[i][j] - a[i-1][j] - a[i] [j-1] + a[i-1][j-1]
从差分数组还原到原矩阵:
p[i][j] = p[i][j] + p[ i -1][j] + p[i][j-1] - p[i-1][j-1]
举例:
有一个矩阵a,如下
- 1 2 4 3
- 5 1 2 4
- 6 3 5 9
差分矩阵p,如下
- 1 1 2 -1
- 4 -5 -1 3
- 1 1 1 2
二维区间修改转化为单点修改
在差分数组中,修改(x1,y1)的值 + c,求前缀之后,黄色的区域都会受到影响
修改(x1,y2) -c (x2,y1) -c,蓝色的部分抵消影响,绿色的部分求前缀多减了c,(x2,y2)+c抵消影响
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3+6;
const int MAXM = 1e3+6;
int a[MAXN][MAXM] = {};
int diff[MAXN][MAXM] = {};
int main() {
int n,m,q;
scanf("%d%d%d", &n, &m, &q);
int i, j;
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
scanf("%d", &a[i][j]);
diff[i][j] = a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
}
}
for (i=0; i<q; i++) {
int x1, y1, x2, y2, c;
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
diff[x1][y1] += c;
diff[x1][y2+1] -=c;
diff[x2+1][y1] -=c;
diff[x2+1][y2+1] += c;
}
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
diff[i][j] += diff[i-1][j]+diff[i][j-1]-diff[i-1][j-1];
printf("%d ", diff[i][j]);
}
printf("\n");
}
return 0;
}