目录
[题目一(大学树木要打药 差分):](#题目一(大学树木要打药 差分):)
[题目二(小明的彩灯 差分):](#题目二(小明的彩灯 差分):)
[题目三(区间更新 差分):](#题目三(区间更新 差分):)
[题目四(劳动课作业 差分):](#题目四(劳动课作业 差分):)
[题目五(大学里的树木要维护 前缀和):](#题目五(大学里的树木要维护 前缀和):)
[题目六(积木大厦 前缀和):](#题目六(积木大厦 前缀和):)
差分和前缀和是常用的数列处理技巧,可以在一维数组或二维数组中快速求解某一区间的和或区间中每个元素的差值。差分可以将原始数列转化为差分数列,而前缀和可以用来求解原始数列中某一区间的和。
差分(Difference): 对于一维数组a,定义差分数组d[i] = a[i] - a[i-1] (i > 0),其中d[0] = a[0]。差分数组d是通过相邻元素的差值得到的,可以用来表示原始数列a中的元素变化情况。例如,对于数组a = [5, 3, 7, 2, 1],其差分数组d = [5, -2, 4, -5, -1]。
前缀和(Prefix Sum): 对于一维数组a,定义前缀和数组s[i] = Σa[j] (0 <= j <= i),其中s[0] = a[0]。前缀和数组s是通过累计相邻元素的和得到的,可以用来表示原始数列a中某一位置之前的元素和。例如,对于数组a = [5, 3, 7, 2, 1],其前缀和数组s = [5, 8, 15, 17, 18]。
差分和前缀和的应用:
- 求解某一区间的和:对于差分数组d,要求解原始数组a中[l, r]区间的和,只需计算前缀和数组s在该区间的差值,即s[r] - s[l-1]。
- 求解某一位置的元素值:对于差分数组d,要求解原始数组a中位置i的元素值,只需计算前缀和数组s在该位置的值,即s[i]。
- 更新某一区间的值:对于差分数组d,要更新原始数组a中[l, r]区间的值,只需将差分数组d在该区间内的元素都加上相应的增量。
差分和前缀和的时间复杂度均为O(n),其中n为数组的长度。差分和前缀和常用于解决区间求和、区间更新等问题,能够优化算法的效率。
题目一(大学树木要打药 差分):
代码:
cpp
#include<iostream>
#include<cstring>
using namespace std;
int n, m;
int a[1000010];
int main()
{
cin >> n >> m;
memset(a, 0, sizeof(a));//初始都为0
for (int i = 0; i < m; i++)//运用差分思想进行操作
{
int l, r, v;
cin >> l >> r >> v;
a[l] += v;
a[r + 1] -= v;
}
int ans = 0;
for (int i = 1; i <= n; i++)//前缀和还原
{
a[i] += a[i - 1];
ans += a[i];
}
cout << ans;
}
题目二(小明的彩灯 差分):
代码:
cpp
#include <iostream>
#include <cstring>
using namespace std;
long long a[100010];
long long b[100010];//差分数组
int main()
{
int n,q;
cin>>n>>q;
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)//差分
{
cin>>a[i];
b[i] = a[i]- a[i-1];
}
while(q--)//操作
{
int l,r,x;
cin>>l>>r>>x;
b[l]+=x;
b[r+1]-=x;
}
for(int i=1;i<=n;i++)
{
b[i] += b[i-1];
if(b[i]<0)
{
cout<<0<<" ";
}
else
cout<<b[i]<<" ";
}
}
题目三(区间更新 差分):
代码:
cpp
#include <iostream>
using namespace std;
long long a[100010],n,m;
long long cha[100010];//差分数组
int main()
{
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)//差分
{
cin>>a[i];
cha[i]=a[i]-a[i-1];
}
while(m--)//操作
{
int l,r,x;
cin>>l>>r>>x;
cha[l]+=x,cha[r+1]-=x;
}
for(int i=1;i<=n;i++)//合并
{
cha[i]+=cha[i-1];
cout<<cha[i]<<" ";
}
cout<<endl;
}
}
题目四(劳动课作业 差分):
代码:
cpp
#include <iostream>
#include <cstring>
using namespace std;
long long a[10000010], n, m;
int main()
{
cin >> n >> m;
memset(a, 0, sizeof(a));
while (m--)
{
int l, r;
cin >> l >> r;
a[l] += 1;
a[r + 1] -= 1;
}
for (int i = 1; i <= n; i++)
{
a[i] += a[i - 1];
cout << a[i] << " ";
}
}
题目五(大学里的树木要维护 前缀和):
代码:
cpp
#include<iostream>
using namespace std;
int n,m;
int a[100010];
int sum[100010];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=a[i]+sum[i-1];//前缀和
}
for(int i=1;i<=m;i++)
{
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
}
题目六(积木大厦 前缀和):
代码:
cpp
#include <iostream>//如1、2、3、4、5,其实只要这五项的和大于15就可以形成递增
using namespace std;
long long a[100010];
long long sum[100010];
long long sums=0;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
sums+=i;
}
if(sum[n]>=sums)
cout<<"YES";
else
cout<<"NO";
}