差分数组 ,前缀和数组的逆

差分数组

差分数组没有所谓的初始化,其实可以当作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中元素的变化量求出最终值。
意会一下啦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值