差分的概念
对于一个数组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+" "); } } }