前缀和 差分
1.一维前缀和 AcWing 795. 前缀和
输入一个长度为n的整数序列。
接下来再输入m个询问,每个询问输入一对l, r。
对于每个询问,输出原序列中从第l个数到第r个数的和。
#include<iostream>
using namespace std;
const int N=100010;
int n,m;
int a[N],s[N];//a[N]用来储存长度为N的整数,s[N]是前缀和数组
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
//求前缀和数组
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
while(m--){
int l,r;
cin>>l>>r;
cout<<s[r]-s[l-1]<<endl;
}
return 0;
}
这段代码实现了利用前缀和的思想来高效处理给定区间内元素和的查询操作。程序首先从输入获取一个整数序列的长度 n
以及查询次数 m
,接着读入整数序列,计算并存储其前缀和数组,之后根据每次输入的查询区间 [l, r]
,利用前缀和数组快速计算并输出该区间内元素的总和。
代码开头包含了 <iostream>
头文件,用于支持标准输入输出操作(例如使用 cin
和 cout
)。通过 using namespace std;
语句,可以在代码中直接使用标准库中的名称,无需显式添加 std::
前缀(不过在大型项目中为避免命名冲突,建议按需显式指定命名空间)。
定义了一个常量 N
,值为 100010
,用于限制后续数组 a
和 s
的大小,这里预先分配固定大小的数组,需要确保实际使用时不会超出这个大小,否则可能导致数组越界等问题。
声明了两个整型变量 n
和 m
,分别用于存储输入的整数序列长度和查询次数。同时声明了两个整型数组 a
和 s
,其中 a
数组用来存储输入的整数序列,s
数组用于存储该整数序列对应的前缀和。
首先通过 cin >> n >> m;
语句从标准输入获取两个整数,分别赋值给 n
和 m
,即确定了整数序列的长度以及后续要进行的区间查询次数。
接着使用一个 for
循环,从索引 1
到 n
遍历,通过 cin >> a[i];
语句依次读入整数序列中的每一个元素,并存储到 a
数组对应的位置中。
这是一个关键的 for
循环,用于计算前缀和数组 s
。它的核心思想是,对于每个位置 i
,前缀和 s[i]
的值等于前一个位置的前缀和 s[i - 1]
加上当前位置在原数组 a
中的元素 a[i]
。例如,s[3]
就是 a[1] + a[2] + a[3]
,通过依次累加,就可以得到整个整数序列的前缀和数组。
这里使用了一个 while
循环,循环条件 m--
表示每进行一次查询操作,m
的值就减 1
,直到 m
的值变为 0
,即完成了所有预定次数的查询操作。
在每次循环中,首先定义两个整型变量 l
和 r
,用于存储从标准输入获取的查询区间的左端点和右端点。
然后通过 cout << s[r] - s[l - 1] << endl;
语句输出查询区间 [l, r]
内元素的总和。其原理是利用前缀和数组的特性,区间 [l, r]
的元素总和等于 s[r]
(表示从第一个元素到第 r
个元素的总和)减去 s[l - 1]
(表示从第一个元素到第 l - 1
个元素的总和),这样就能快速计算出区间内元素和,而无需每次都重新遍历区间内的所有元素进行求和,大大提高了查询效率。
最后 main
函数返回 0
,表示程序正常结束。
2.二维前缀和 AcWing 796. 子矩阵的和
输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
#include<iostream>
using namespace std;
const int N=1010;
int n,m,q;
int a[N][N],s[N][N];
int main()
{
scanf ("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j