前缀和和差分模板(AcWing 795-798)

前缀和分一维前缀和和二维前缀和,前缀和可以帮我们快速统计一段范围内的合。

需要简单的理解

一维前缀和 —— 模板题 AcWing 795. 前缀和
S[i] = a[1] + a[2] + ... a[i];
a[l] + ... + a[r] = S[r] - S[l - 1];

二维前缀和 —— 模板题 AcWing 796. 子矩阵的和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1];

差分需要一定的理解。

/*

给定原数组a[1],a[2],...a[n],构造差分数组b[N],使得a[i] = b[1] + b[2]+ ...b[i],一般假定初始全为0,用insert(i, i, a[i])即可构造出b[N]
核心操作:将a[L~R]全部加上C,等价于:b[L] += C, b[R + 1] -= C*/重点

#include <iostream>
using namespace std;

const int N = 100010;

int n, m;
int a[N], b[N]; // b为a的差分

// a数组中[l, r]区间内都加上c
void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        insert(i, i, a[i]);
    }

    while (m--)
    {
        int l, r, c;
        scanf("%d%d%d", &l, &r, &c);
        insert(l, r, c);
    }

    for (int i = 1; i <= n; i++)
    {
        b[i] += b[i - 1];
        printf("%d ", b[i]);
    }

    return 0;
}

二维的差分更难理解。慢慢来吧~

前缀和差分是2个互逆的运算,假设最开始的数组是a[i], 则前缀和数组sum[i]表示从a[1]+..+a[i];而差分数组b[1]+…+b[i]则表示a[i],即a[i]是差分数组b[i]的前缀和;
所以b[i][j]表示 b[1][1]+…+b[i][j]从图上刚好构成一个矩阵,
所以当a[i][j]+c,从b数组构成的矩阵上来看就是b[i][j]这一个小矩阵加上c,画出图之后比较容易可以看出公式为:b[i][j] += c, b[i + 1][j] -= c, b[i][j + 1] -= c, b[i + 1][j + 1] += c;

中间可以并在一起写,但是为了方便初学者刚学,还是分开输入输出一步一步来暗部就按比较容易理解。

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e3 + 40;
int a[maxn][maxn], b[maxn][maxn];

inline void insert(int x1, int y1, int x2, int y2, int c) {
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}

int main(void) {
    int n, m, q;
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            scanf("%d", &a[i][j]);

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            insert(i, j, i, j, a[i][j]);

    for(int i = 1; i <= q; i++) {
        int x1, y1, x2, y2, c;
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
        insert(x1, y1, x2, y2, c);
    }

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(j == m) printf("%d\n", b[i][j]);
            else printf("%d ", b[i][j]);

    return 0;
}

原文地址:https://www.cnblogs.com/zyz010206/p/12334169.html

时间: 2024-11-08 03:49:35

前缀和和差分模板(AcWing 795-798)的相关文章

浅谈简单前缀和与差分问题

\(Part1:\) 前缀和与差分的简单定义 考虑一个数组\(A\),其项数为\(n\)项.有\(m\)次询问,每次询问给定两个参数\(l\)和\(r\),要求求出\(A[l]+A[l+1]+...+A[r]\). 怎么做呢? 暴力:显然是\(O(nm)\)的 数据结构维护:显然是\(O(mlogn)\)的 前缀和的用处就在于可以将这样的序列区间求和的问题用\(O(n+m)\)的复杂度,在线性的时间和空间内解决出. 那么前缀和究竟是什么呢? 在读入\(A\)数组的时候,我们预处理出一个前缀和数组

AcWing&#160;795.&#160;前缀和

题目地址  https://www.acwing.com/solution/AcWing/content/2075/ 题目描述输入一个长度为n的整数序列. 接下来再输入m个询问,每个询问输入一对l, r. 对于每个询问,输出原序列中从第l个数到第r个数的和. 输入格式第一行包含两个整数n和m. 第二行包含n个整数,表示整数数列. 接下来m行,每行包含两个整数l和r,表示一个询问的区间范围. 输出格式共m行,每行输出一个询问的结果. 算法简单前缀和 主要是记住模板 记住边界问题 C++ 代码 1

ACwing : 798. 差分矩阵

不得不说之前的差分我真的是掌握的不好.. 一维差分确实简单一看就会,但是学会了之后却并不能灵活的运用. 而二维的差分我甚至还琢磨了很长时间 懒得画图所以没有图..对于二维差分的定义,百度百科是这么说的 顾名思义,就是在矩阵中,一行(一列)的元素与上一行(上一列)对应元素的差值,依次排列在上一行(上一列)元素对应所在位置. (好像说的是矩阵差分,但是问题不大) 但是只要你用模板代码打出一个差分数组就会发现这个数组的排列并不规律,换句话说我并没有看懂这个.. 因此我们完全可以忽略差分数组一个点的意义

前缀和与差分

Day4整理的时候忘了这一块了..我现在补上它. 并不难理解. 前缀和 其实可以把它理解为数学上的数列的前n项和(对于一个一维数组的前缀和). 我们定义对于一个数组a的前缀和数组s,s[i] = a[1]+a[2]+...+a[i]. 二维前缀和 与一维前缀和类似,设s[i][j]表示所有a[i'][j']的和.(1≤i'≤i,1≤j'≤j) 有一点像"矩形的面积"那样,把一整块区域的值都加起来. 前缀和的用途 一般用来求区间和. 对于一维情况,现在我给出一个数列a,要求你回答m次询问

前缀和、二维前缀和与差分

前缀和 假如给出一串长度为n的数列a1,a2,a3...an,再给出m个询问,每次询问给出L,R两个数,要求给出数列在区间[L,R]的和 普通的方法,时间复杂度为O(n*m) int a[100005]; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int sum=0; while(m--){ for(int i=L;i<=R;i++){ sum+=a[i]; } } 前缀和就是前面i个数的总和,对于每个询问,只需要输出a

基础算法 --- 前缀和与差分

前缀和 一个数列A,它的前缀和数列S是能够通过数学方式推断出来的: 部分和 数列A中某个下标区间内和数的和,即: S[i, j]=S[j] - S[i - 1] 前缀和与部分和应用场景 给定m个区间,求每个区间内数的和: 暴力解法:m次循环,循环内部再进行区间循环,这种解法在小量数据场景无问题,如果数值大,会造成超时. 前缀和解法:先计算前缀和,然后循环m次,求每个区间部分和 差分 一个数列A:1.2.3.4.5,它的差分数列为B:1.1.1.1.1,那么有如下特性: 1.数列B的前缀和S[i]

Educational Codeforces Round 52 (Rated for Div. 2)【A,B,C】【C题:贪心+约束差分模板】

水题.仔细看题 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 #define int long long 5 signed main(){ 6 int _; 7 cin>>_; 8 while(_--){ 9 int s,a,b,c; 10 cin>>s>>a>>b>>c; 11 int ans=0; 12 ans=(s/(a*c))*a+(s/(a*c))*b+(s%(a*

差分模板

一维差分: 给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c 二维差分: 给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c: S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c 原文地址:https://www.cnblogs.com/qdu-lkc/p/12202489.html

归并排序模板(ACwing 787)

归并排序其实也是分治的思想 首先归并排序跟快排一样同样需要考虑分界点 归并排序的分界点都是取中间值 其次归并排序需要递归排序左边和右边 最后一部也是最难的一部需要将分开的归并排序合二为一 #include<iostream> using namespace std; int n; const int N= 100010; int a[N],tmp[N];//归并排序需要多定义一个数组 void merge_sort(int a[],int l,int r) { if(l>=r)retur