-
http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/4107.html
- 差分数组de定义:记录当前位置的数与上一位置的数的差值.
- 栗子
- 容易发现的是,∑ b[j](j = 1 to i)即代表a[i] 的值. (∑ 即代表累加.)
- 看到前面的∑ 你一定会发现这是前缀和!
- 那你认为这是前缀和? 的确是qwq.
- 实际上这并不是真正意义上的前缀和.
- 前缀和的思想是 根据元素与元素之间的并集关系(和的关系),求出某些元素的和的值.对应的为∑ a[j](j = 1 to i)
- 而差分的思想与此不同.
- 差分的思想是 根据元素与元素之间的逻辑关系(大小关系),求出某一位置元素的值.对应的为∑ b[j](j = 1 to i)
- What?不懂?看下面
- 继续捡起刚刚的栗子.
- 有没有发现不同之处 ( ω )
- 差分数组有什么用?
- 先看一道题,
- 有n个数。
- m次操作,每一次操作,给定l,r,del.将l~r区间的所有数增加del;
- 最后有q个询问,给你 l,r ,每一次询问求出l~r的区间和。
- PS: 先进行m个修改操作,后进行查询操作.
- 如果你是一个巨佬,你会"woc,线段树裸题!" "woc,树状数组裸题!"
- 然而,今天我要BB的不是这些东西.
- 是差分数组的运用!
- 有没有想法? 没有的话那就我来有也是我来
- 考虑我们差分数组记录的是什么,它记录的是当前位置的数与上一个数的差值.
- 如果我们在差分数组的 b_x减去del 在b_{y+1}位置处加上del,就能达到整个区间修改的操作.
- 什么?不相信? 那我们来个栗子(要糖炒的
- 还是刚开始的栗子.
- 这样是不是达到了区间修改操作,是不是! "是!,tql!!"
- 这样我们就能做到O(1)修改啦!
- 我们再定义两个数组(先不要忘记我们的差分数组为b_i
- s_i代表∑ b[j](j = 1 to i) (其实就是代表a[i] qwq)
- sum_i代表∑ s[j](j = 1 to i) 即代表前缀和. qwq
- 容易发现的是 sum_r -sum_{l-1}=∑ s[j](j = 1 to i)
- 什么不理解为什么是l-1?
- 那我们把式子展开看 qwq
- 所以说我们可以在修改操作完成之后,O(n)的计算我们的sum数组,然后在询问的时候O(1)的输出了.
- 具体这个题的代码是这样的↓
- 快速处理区间加减操作:O(1)询问区间和:O(n)处理O(1)查询.
- 你以为差分只有这么多用处吗?
- 利用差分数组还能算出前缀和,看式子变形!
- 所以说,上面的代码完全可以改一下,相信大家写出来应该会很容易.
- 差分还有其他用途这里并没有涉及到,所以还需要大家自己去发现去学习 ┓( ` )┏
-
#include<bits/stdc++.h> using namespace std; #define maxn 123456 #define ll long long ll n,v,sum[maxn],maxx; ll a[maxn],m,l,r,ans[maxn]; int main() { while(~scanf("%lld%lld",&n,&m)) { maxx=0; memset(a,0,sizeof(a)); memset(sum,0,sizeof(sum)); memset(ans,0,sizeof(ans)); for(int i=1; i<=n; i++) { scanf("%lld%lld%lld",&l,&r,&v); a[l]+=v; a[r+1]-=v; maxx=max(l,max(r,maxx)); } for(int i=1; i<=maxx; i++) sum[i]+=sum[i-1]+a[i]; for(int i=1; i<=maxx; i++) ans[i]+=ans[i-1]+sum[i]; while(m--) { scanf("%lld%lld",&l,&r); printf("%lld\n",ans[r]-ans[l-1]); } } return 0; }
SDUT-4107-金泽的地图-差分数组第一弹
最新推荐文章于 2024-12-10 16:14:18 发布