AcWing
  • 首页
  • 活动
  • 题库
  • 竞赛
  • 应用
  • 更多
    • 题解
    • 分享
    • 商店
    • 问答
    • 吐槽
  • App
  • 登录/注册

AcWing 797. 差分_java    原题链接    简单

作者: 作者的头像   dongwa_zzuli ,  2020-04-03 18:02:26 ,  所有人可见 ,  阅读 1868


20


15

什么是差分

差分是求前缀和的逆操作,对于原数组a[n],构造出一个数组b[n],使a[n]为b[n]的前缀和。一般用于快速对整个数组进行操作,比如对将a数组中[l,r]部分的数据全部加上c。使用暴力方法的话,时间复杂至少为O(n),而使用差分算法可以将时间复杂度降低到O(1)。

算法思路

拥有数组b[n]后,想要对a数组中所有的数据加上c,只需要将b[1]+c即可,因为a[i]是b[i]的前缀和,a[i]=b[1]+b[1]+b[3]+……+b[i]。b[1]是所有的a[i]都拥有的子元素,将b[0]+c,那么a[n]中所有的数据都会加上c。如果想将a数组中[l,r]部分的数据全部加上c,只需要将b[l]+c,然后b[r+1]-c即可。

差分操作和前缀和一样数组下标都从1开始。

b[l]+c后,l后面的数组都会加c。r后面的数据也会被改变,要改回来就得b[r+1]-c

如何构造b[n]

构造b[n]看起来很难,其实根本就不用刻意去构造它。
如果将a数组中[l,r]部分的数据全部加上c看作一次插入操作,那么构造的过程可以看作是将a进行了n次插入操作。第一次在[1,1]的范围插入了a[1],第二次在[2,2]范围插入a[2],第二次在[3,3]范围插入a[3]……,以此类推,进行n次插入后,那么数组a就正好是数组b的前缀和了。

例题

原题链接
输入一个长度为n的整数序列。

接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。

请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数n和m。

第二行包含n个整数,表示整数序列。

接下来m行,每行包含三个整数l,r,c,表示一个操作。

输出格式

共一行,包含n个整数,表示最终序列。

数据范围

1≤n,m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000

输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
输出样例:
3 4 5 3 4 2

java代码

package 差分;

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {
    static int  N = 100010;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(new BufferedInputStream(System.in));
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        //a为原数组,b为差分数组
        int[] a = new int[N];
        int[] b = new int[N];

        for (int i = 1; i <= n; i++) { 
            a[i] = scanner.nextInt();
        }
        //进行n次插入,初始化差分数组
        for(int i=1;i<=n;i++) {
            insert(b, i, i, a[i]);          
        }

        while(m-->0) {
            int l,r,c;
            l = scanner.nextInt();
            r = scanner.nextInt();
            c = scanner.nextInt();
            insert(b, l, r, c);
        }
        //经过一系列插入操作后,现在答案数组应该是b数组的前缀和,让b数组变成b的前缀和。
        //公式 b[i] = b[i-1] + b[i] 
        for(int i=1;i<=n;i++)b[i] +=b[i-1];

        for(int i=1;i<=n;i++)System.out.print(b[i]+" ");
        System.out.println();
        scanner.close();
    }

    //插入操作函数
    public static void insert(int[] a,int l,int r,int c) {
        a[l]+=c;
        a[r+1]-=c;
    }
}

6 评论


用户头像
2098274677   2021-06-02 22:32         踩      回复

a[ i ]不是应该等于b[ 1 ]+b[ 2 ]+b[ 3 ]+、、、+b[ i ]的吗???怎么就是全部b数组的和等于a[ i ]了。’

用户头像
dongwa_zzuli   2021-06-03 11:05         踩      回复

你指的是文中那一句话呢?

用户头像
2098274677   2021-06-03 14:56    回复了 dongwa_zzuli 的评论         踩      回复

算法思路第二行

用户头像
dongwa_zzuli   2021-06-03 17:16    回复了 2098274677 的评论         踩      回复

谢谢指正,已修改


用户头像
培弋   2021-05-27 22:00         踩      回复

最难理解的就是b[n]的构造,首先b[n]初始化为都为0。insert(i,i,val),就是第i个数加上val,第i+1个数减去val。那么对前i个赋值后b【i+1】是多少呢。答案是:b[i+1]=-a[i](未给b[i+1]赋值的情况),那赋值之后呢b[i+1]=a[i+1]-a[i]。所以a[i+1]=b[1]+.....+b[i+1]。当然给当前值加上val后,会给下一个值减去val,可能会有边界情况,但是我们只遍历到n,n+1不管了,当然要多开空间防止报错。这个也是看楼主的题解,理解的,希望给后来的人节约点时间。

用户头像
世蒂   8个月前         踩      回复

理解了,谢谢分享


你确定删除吗?
1024
x

© 2018-2023 AcWing 版权所有  |  京ICP备17053197号-1
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标
请输入绑定的邮箱地址
请输入注册信息