数列游戏——差分

数列游戏

Description

给定一个长度为N的序列,首先进行A次操作,每次操作在Li和Ri这个区间加上一个数Ci。然后有B次询问,每次询问Li到Ri的区间和。

初始序列都为0。

Input

对于每组数据,第一行三个整数N A B。(1<=N<=1000000,1<=A<=N,A<=B<=N)

接下来A行,每行三个数Li Ri Ci。(1<=Li<=N,Li<=Ri<=N,|Ci|<=100000000000000)。

接下来B行,每行两个数 Li Ri。范围同上。

Output

对于每次询问,输出一行一个整数。因为最后的结果可能很大,请对结果mod 1000000007。

Sample Input

5 1 1
1 3 1
1 4

Sample Output

3

思路:

  如果我们按照暴力的方法来,每次修改都对r到l区间增加c的话,那么答案是肯定的:Time Limit Exceeded(时间超时),注意一下啊,这道题不是边增加区间的值边询问的,而是将所有l到r的区间都增加了之后,才开始询问的,所以,我们只需要维护一个差分数组就可以了。

  怎么维护呢?其实很简单,只需要O(2)的时间,如果将L到R的区间增加C,那么我们只需要对差分数组D的D[L]和D[R+1]进行操作就可以了,怎么操作呢?我们来举一个例子:A为1,2,3,4,5,那么A的差分数组D应该是1,1,1,1,1,然后我们对区间[2,4](2,3,4)进行加2操作,A就变成了1,4,5,6,5,现在的D是什么呢?D就是1,3,1,1,-1,发现什么没有?

  在增加了区间值之后,D只改变了两个地方,那就是D[L]和D[R+1]变了,怎么变了呢?D[L]+=2了,D[R]-=2,对不对?这个2是什么呢?就是我们将区间里面加的C啊,这样子,我们的差分数组就维护成功了,但是为什么是这样子呢?我们来证明一下:

  我们将A[L]到A[R]的区间内加上C,在D数组里(差分数组),从1~L-1, 是不会改变的,因为D[L-1]=A[L-1]-A[L-2],A[L-1]和A[L-2]的值是并没有改变的。

  我们来看看D[L]=A[L]-A[L-1],A[L-1]是没有变的,但是A[L]增加了C,所以维护差分数组之后D[L]+=C,我们来看L+1~R,D[L+1]=A[L+1]-A[L]的值和区间没有增加的时候是一样的,为什么呢?因为A[L+1]和A[L]都加了C,所以减起来还是差不变,D[R]也是一样。

  我们来看看D[R+1]=A[R+1]-A[R],因为A[R]加了C,相当于多减了一个C,所以维护差分数组是D[R+1]-=3.

  求出了维护之后的差分数组D,我们可以重新求出新的数组A,怎么求呢?差分数组求出的是前后两个值的差,我们只需要将A[i]定义为A[i-1]+D[i]就可以了,这样重新求出了A这个数组,那我们怎么求A数组的区间和呢?这个就可以用到前缀和算法了,用S求出A的前缀和S[i]=S[i-1]+A[i],S[0]=A[0]=0,这样我们最后输出S[R]-S[L-1]就可以了!(因为S[R]求的是A[1]加到A[R]的,A[L-1]是A[1]加到A[L-1]的,两者相减,就是S[L]加到S[R]的值了)

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100000;
const int mod=1e9+7;
int main(){
	int n,m,k;
	int d[N],a[N],s[N];
	memset(d,0,sizeof(d));
	memset(a,0,sizeof(a));
	memset(s,0,sizeof(s));
	scanf("%d%d%d",&n,&m,&k);
	long long sum=0;
	for(int i=1,x,y,z;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		d[x]=(d[x]+z)%mod;
		d[y+1]=(d[y+1]-z)%mod;
	}
	for(int i=1;i<=n;i++)
	  a[i]=(d[i]+a[i-1])%mod;
	for(int i=1;i<=n;i++)
	  s[i]=(s[i-1]+a[i])%mod;
	for(int i=1,x,y;i<=k;i++){
		scanf("%d%d",&x,&y);
		cout<<s[y-1]-s[x-2]<<endl;
	}
	return 0;
}

 总结:

  此题是差分算法的入门题,算是很简单的了,需要熟练掌握前缀和的知识后学习。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙星尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值