zoukankan      html  css  js  c++  java
  • 差分

    • 差分就是数组 a 构造一个查分数组 b (一般选择值为0的两个数组),差分数组 b 的相应位置的前缀和代表了数组 a 中每个位置的结果,对于在一个区间里增加或者减小某个数,对于前缀和来说是o1的,所以对于a中某个区间进行同样的操作也是o1,对a矩阵的操作等价于对b矩阵的操作
    • 一维

    如果想要在数组a的 l 到 r 区间的每个数增加 c ,我们可以想到的一种办法是线性扫描一遍,复杂度为n级别,是否可以做到复杂度为1呢?

    利用差分可以实现,我们需要一个辅助数组b,其实 a 中每个元素均为 b 数组中对应位置的前缀和,采用b【l】 += c,b【r+1】-= c 可以实现数组 a 从 l 到 r 每个元素增加 c ,由于只有两条语句,所以时间复杂度是1的,最后我们需要把b数组的前缀和求出可得数组 a ,具体请看下面的代码(c++实现)

     1 #include <iostream>
     2 #include <vector>
     3 
     4 using namespace std;
     5 
     6 const int N = 100000+10;
     7 
     8 //构造了一个a的差分数组b,因为此时a数组中 a[i] = b[1] + b[2] + ... + b[i]; a数组为b数组的前缀和
     9 vector<int> a(N,0);
    10 vector<int> b(N,0);
    11 
    12 int n, m;
    13 
    14 //从a数组的 l 到 r区间内插入c,也就是在b数组的 l 处插入c 在 r+1 处 - c,因为a数组是b的前缀和
    15 void insert(int l, int r, int c){
    16     b[l] += c;
    17     b[r + 1] -= c;
    18 }
    19 
    20 int main(){
    21     cin >> n >> m;
    22     for(int i = 1;i <= n;++i) cin >> a[i];
    23     
    24     for(int i = 1;i <= n;++i) insert(i, i, a[i]);//相当于从i 到 i 区间每个数增加c ,表现在b 数组上
    25     
    26     for(int i = 0;i < m;++i){
    27         int l, r, c;
    28         cin >> l >> r >> c;
    29         insert(l, r, c);//从 l 到 r 区间插入 c ,表现在b上, 但是实质在a上,因为一会要求b 的 前缀和
    30     }
    31     
    32     for(int i = 1;i <= n;++i) a[i] = a[i - 1] + b[i];//a[i] 为 b[i] 的前缀和 ,就是a[i] 从l 到 r 之间每个数增加c的结果
    33     
    34     for(int i = 1;i <= n;++i) cout << a[i] << " ";
    35     
    36     return 0;
    37 }
    View Code
    •  二维
     1 #include <iostream>
     2 #include <vector>
     3 
     4 using namespace std;
     5 
     6 const int N = 1000+10;
     7 //构造a是b的前缀和矩阵,b是a的差分矩阵
     8 vector<vector<int>> a(N,vector<int>(N,0));
     9 vector<vector<int>> b(N,vector<int>(N,0));
    10 
    11 int n, m, q;//n 行 m 列
    12 // x1,y1 为左上角下标 x2,y2为右下角下标 , 函数功能为在 x1,y1 and x2,y2 构成的矩阵每个元素加 c 
    13 void insert(int x1, int y1, int x2, int y2, int c){
    14     b[x1][y1] += c;    
    15     b[x2 + 1][y1] -= c;
    16     b[x1][y2 + 1] -= c;
    17     b[x2 + 1][y2 + 1] += c;
    18 }
    19 
    20 int main(){
    21     cin >> n >> m >> q;    
    22     
    23     for(int i = 1;i <= n;++i)
    24         for(int j = 1;j <= m;++j)
    25             cin >> a[i][j];
    26             
    27     for(int i = 1;i <= n;++i)
    28         for(int j = 1;j <= m;++j)
    29             insert(i, j, i, j, a[i][j]);
    30             
    31     for(int i = 0;i < q;++i){
    32         int x1,y1,x2,y2,c;
    33         cin >> x1 >> y1 >> x2 >> y2 >> c;
    34         insert(x1, y1, x2, y2, c);
    35     }
    36     
    37     for(int i = 1;i <= n;++i){
    38         for(int j = 1;j <= m;++j){
    39             a[i][j] = a[i-1][j] + a[i][j-1] - a[i-1][j-1] + b[i][j];//计算b的前缀和赋值给a
    40             cout << a[i][j] << " ";
    41         }
    42         cout << endl;
    43     }
    44     
    45    return 0; 
    46 }
    View Code
  • 相关阅读:
    开课 博客
    给定数组求数组中和最大子数组的和
    课堂测验
    读梦断代码有感(3)2019.2.20
    读梦断代码有感(2)2019.2.10
    读梦断代码有感(1)2019.2.05
    进度七
    进度 六
    sjz地铁作业
    进度四
  • 原文地址:https://www.cnblogs.com/sxq-study/p/12069735.html
Copyright © 2011-2022 走看看