差分
差分就是前缀和的逆运算
一维差分
有一个数组
构造
使得.
构造方法也很简单:
- ...
其实就是假想了一个b数组,使得a数组是它的前缀和。
比如我们想要a数组[l,r]区间内的数都加上c
那么只需要 并且,这样求前缀和得到的a数组就可以在[l,r]区间都加上了c
这样我们只需要在O(1)的时间就可以在原数组某一个区间内加上固定的值,并且通过对b数据求前缀和就可以在O(n)的时间内得到a数组
实际构造的时候我们可以假定a数组初始全部为0,则差分b数组也全部为0
我们可以将给定的值看作进行了n次插入操作,第一次让[1,1]区间加上,第二次是让[2,2]加上...
这样差分就不需要自己进行构造,想他是怎么算出来的了。
应用题目
输入一个长度为n的整数序列。
接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。
请你输出进行完所有操作后的序列。
输入格式
第一行包含两个整数n和m。
第二行包含n个整数,表示整数序列。
接下来m行,每行包含三个整数l,r,c,表示一个操作。
输出格式
共一行,包含n个整数,表示最终序列。数据范围
1 ≤ n,m ≤ 100000,
1 ≤ l ≤ r ≤ n,
-1000 ≤ c ≤ 1000,
-1000 ≤ 整数序列中元素的值 ≤ 1000输入样例
6 3 1 2 2 1 2 1 1 3 1 3 5 1 1 6 1
输出样例
3 4 5 3 4 2
代码
import java.util.*;
public class Main{
static Scanner scanner = new Scanner(System.in);
static final int N = 10010;
static int n = scanner.nextInt();
static int m = scanner.nextInt();
static int[] a = new int[N];
static int[] b = new int[N];
public static void insert(int l, int r, int c)
{
b[l] += c;
b[r+1] -= c;
}
public static void main(String args[]) throws Exception {
for(int i = 1; i <= n; i++)
a[i] = scanner.nextInt();
for(int i = 1; i <= n; i++)
insert(i,i,a[i]);
while(m-- > 0)
{
int l=scanner.nextInt();
int r=scanner.nextInt();
int c=scanner.nextInt();
insert(l,r,c);
}
for(int i = 1; i <= n; i++)
b[i] += b[i-1];
for(int i = 1; i <= n; i++)
System.out.print(b[i] + " ");
}
}
二维差分
原矩阵,构造差分矩阵,满足原矩阵是差分矩阵的前缀和就可以
一维差分是每次给一段区间加上一个值,那么二维差分就是给其中的一个子矩阵加上一个值。
比方说要给红色区域都加上一个值,如下图:
- 令,则这个点右下角所有部分都会加c,即蓝色框框部分。
- 由于非红色部分不需要加c,所以我们需要将阴影部分减c,操作如下:
- 将紫色区域部分都减去c, ,
- 将绿色部分也减去c, ,
- 最后加上减去了2遍的紫绿相交部分, ,
初始化:
- 假设,则也为0
- 将的元素依次插入就可以了,看作左上角是[i,j],右下角也是[i,j]就可以了
例题
输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数x1,y1,x2,y2,c, 其中(x1,y1)和(x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素值都加上c。
请你将进行完所有操作后的矩阵输出
输入格式
第一行包含三个整数n,m,q。
接下来n行,每行包含m个整数,表示整数矩阵。
接下来q行,每行包含5个整数x1,y1,x2,y2,c, 表示一个操作。
输出格式
共n行,每行m个整数,表示所有操作进行完毕后的最终矩阵。
数据范围
1 ≤n, m ≤ 1000,
1 ≤ q ≤ 100000,
1 ≤ x1 ≤ x2 ≤ n,
1 ≤ y1 ≤ y2 ≤ m,
—1000 ≤ c ≤ 1000
—1000 ≤ 矩阵内元素的值 ≤ 1000输入样例
3 4 3 1 2 2 1 3 2 2 1 1 1 1 1 1 1 2 2 1 1 3 2 3 2 3 1 3 4 1
输出样例
2 3 4 1 4 3 4 1 2 2 2 2
代码
import java.util.*;
public class Main{
static Scanner scanner = new Scanner(System.in);
static final int N = 1010;
static int n = scanner.nextInt();
static int m = scanner.nextInt();
static int q = scanner.nextInt();
static int[][] a = new int[N][N];
static int[][] b = new int[N][N];
public static void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
public static void main(String args[]) throws Exception {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] = scanner.nextInt();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
insert(i,j,i,j,a[i][j]);
while(q-- > 0)
{
int x1=scanner.nextInt();
int y1=scanner.nextInt();
int x2=scanner.nextInt();
int y2=scanner.nextInt();
int c=scanner.nextInt();
insert(x1,y1,x2,y2,c);
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++) System.out.print(b[i][j] + " ");
System.out.println();
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本