差分数组
差分数组没有所谓的初始化,其实可以当作a数组起初全零,a对应的差分数组也自然是全零,那么初始化就相当于进行了n次利用差分的修改操作
【1,1】区间加上a【1】,【2,2】区间加上a【2】,【3,3】区间加上a【3】,这样子
差分不用考虑构造,其实初始的构造就是进行n次插入
用于对数组中 某个区间【l,r] 的所有元素 全部进行相同的加减操作(据说还有神奇的操作),为了避免最坏的情况,假设数据10^5, 每次对1~10的5次方 所有数据进行加减,10的10次方,铁定超时
(如果给的时间是1s,一般要控制在10的8次方以内)
for(int i=0;i<n;i++){
a[i]+=1;
}
for(int i=1;i<n;i++){
a[i]+=1;
}
for(int i=2;i<n;i++){
a[i]+=1;
}
.
.
.
那么怎么把每次操作时间复杂度从n降到常数量级呢?
用前缀和的差分数组differ[]
cin>>l>>r>>change;//l r为端点 change为修改的值
diff[l] += change;
diff[r + 1] -= change;
这里有道题,
1674. 使数组互补的最少操作次数
emm,我将就这样做了,把差分数组取名differ 比 cnt 更好
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char** argv) {
int n;
cin>>n;
int nums[n];
int limit;
cin>>limit;
for(int i=0;i<n;i++){
cin>>nums[i];
}
int cnt[limit*2+5];
memset(cnt,0,sizeof(cnt));
cnt[2]+=2;//给cnt数组2~2*limit范围的数都加上2 ,只需以下两步
cnt[2*limit+1]-=2;
for(int i=0;i<n/2;i++){
int minx=min(nums[i],nums[n-1-i]);
int maxx=max(nums[i],nums[n-1-i]);
// int l=2; //对于 加2的操作,就提前做了,如果是加1 的情况就为它们 减1
// int r=minx;
// cnt[l]+=2;//给cnt数组2~2*limit范围的数都加上2 ,只需以下两步
// cnt[r+1]-=2;
int l=minx+1;
int r=minx+maxx;
cnt[l]+=-1;
cnt[r+1]-=-1;
l=minx+maxx+1;
r=limit+maxx;
cnt[l]+=-1;
cnt[r+1]-=-1;
l=minx+maxx;//单独对 cnt[i]
cnt[l]+=(-2); // 1 3 5 8--->1 1 5 8
cnt[l+1]-=(-2) ; // 1 2 2 3--->1 0 4 3
}
int count=0;
int res=0x3f3f3f3f;
for(int i=2;i<=limit*2;i++){
count+=cnt[i];//此时的count就是 使所有数对 数对之和为i的操作数
res=min(res,count);
}
cout<<res<<endl;
return 0;
}
一道差分基础题
差分
做法有二:
#include <bits/stdc++.h>
using namespace std;
//const int N =1e5+5;
const int N=100005;
int a[N];
int diff[N];
int main(){
int n,m;
cin>>n>>m;
memset(diff,0,sizeof(diff));
for(int i=1;i<=n;i++){
cin>>a[i];
// diff[i]=a[i]-a[i-1];
}
int l,r,c;
while(m--){
cin>>l>>r>>c;
diff[l]+=c;
diff[r+1]-=c;
}
for(int i=1;i<=n;i++){
diff[i]+=diff[i-1];
a[i]+=diff[i];
cout<<a[i]<<" ";
}
return 0;
}
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = a[i] - a[i - 1]; //构建差分数组
}
int l, r, c;
while (m--)
{
scanf("%d%d%d", &l, &r, &c);
b[l] += c; //将序列中[l, r]之间的每个数都加上c
b[r + 1] -= c;
}
for (int i = 1; i <= n; i++)
{
a[i] = b[i] + a[i - 1]; //前缀和运算
printf("%d ", a[i]);
}
return 0;
}
第一种做法,diff【】差分数组其实不是典型意义的数组,即 diff【i】元素正正好好地表示a[i]-a[i-1],而是记录了 数组a中各元素变化量的 差分,其实意义相同,第二种先求了原始a数组中的差分,在这基础上改变差分数组的值,最后直接通过该差分数组求出a中元素的值,而前者初始默认各元素变化量都为0,故差分数组元素都为0,最后要通过求前缀和求出某个元素的统共变化量,再通过a中元素的变化量求出最终值。
意会一下啦!