SDUT-4107-金泽的地图-差分数组第一弹

本文深入探讨差分数组的概念及应用,通过实例讲解如何利用差分数组进行区间修改操作,实现O(1)时间复杂度。同时,介绍如何通过差分数组计算前缀和,提升算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  •  
  • 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;
    }
  •  
  •  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值