差分法详细

差分的概念

对于一个数组a[],差分数组diff[]的定义是:

diff[i]=a[i]-a[i-1]

对差分数组做前缀和可以还原为原数组

        diff[1]=a[1]

        diff[2]=a[2]-a[1]

        diff[3]=a[3]-a[2]

        diff[n]=a[n]-a[n-1]

diff[1]+diff[2]+diff[3]+...+diff[i]

=a[1]+(a[2]-a[1])+(a[3]-a[2])+...+(a[i]-a[i-1])

=a[i]

差分数组的主要作用

快速将数组A的区间[l,r]加d(即:把Al,A(l+1)...+Ar这几个元素各加上d)

一般的计算方法,需要对区间内所有元素进行遍历并分别加上d。所以时间复杂度是O(n)

若题目要求进行m次这样的区间操作,则时间复杂度变为O(m*n)

而差分则可以将在原序列上的“区间操作”转化为差分序列上的“单点操作”

diff[l]+=d;

diff[R+1]-=d;

 因此,使用差分可以将单次区间操作的时间复杂度优化到O(1),m次查询的总时间复杂度优化到O(m)

最后,若将差分序列转化为原序列,最终的时间复杂度是O(n+m)

差分的模板

public static void chaifen1(int []arr,int i,int r,int d){

        arr[l]+=d;

        arr[r+1]-=d;

}

例题实战

小明拥有N个彩灯,第i个彩灯的初始亮度为ai;

小明将进行Q次操作,每次操作可选择一段区间,并使区间内彩灯的亮度+x(x可能是负数)

求Q次操作后每个彩灯的亮度(若彩灯亮度为负数则输出0)

输入描述

第一行包含两个正整数N,Q,分别表示彩灯的数量和操作的次数

第二行包含N个整数,表示彩灯初始的量亮度

接下来Q行每行包含一个操作,格式如下:

l r x,表将区间l~r的彩灯的亮度+x

1<=N,Q<=5*10^5,0<=ai<=10^9,1<=l<=r<=N,-10^9<=x<=10^9

输出描述

输出共1行,包含N个整数,表示每个彩灯的亮度。

示例

5 3

2 2 2 1 5

1 3 3 

4 5 5

1 1 -100

package Absent;

import java.util.Scanner;

public class Chapter3 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan=new Scanner(System.in);
		int N=scan.nextInt();//数量
		int Q=scan.nextInt();//操作次数
		
		int arr[]=new int[N];
		for(int i=0;i<N;i++) {
			arr[i]=scan.nextInt();
		}//传入初始亮度
		long []diff=new long[N+1];//不用判断是否i+1会超出数组索引
		for(int i=0;i<Q;i++) {
			int l=scan.nextInt()-1;//数组是0-N的,区间是1-N的
			int r=scan.nextInt()-1;
			int d=scan.nextInt();
			diff[l]+=d;
			diff[r+1]-=d;
			
		}//初次操作
		for(int i=1;i<N;i++) {
			diff[i]+=diff[i-1];
		}//还原数组
		for(int i=0;i<N;i++) {
			long x=arr[i]+diff[i];
			x=Math.max(0, x);//不用去判断是否大于0
			System.out.print(x+" ");
		}
		
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值