数据结构之差分数组

2019-06-25

推荐博客阅读:https://www.sohu.com/a/271430685_100201031

一. 适合解决的问题

有n个数。m次操作,每一次操作,给定l,r,del.将l~r区间的所有数增加del;最后有q个询问,给你 l,r ,每一次询问求出l~r的区间和。

注明: 先进行m个修改操作,后进行查询操作.

涉及到的用途有

  • 快速处理区间加减操作:O(1)
  • 询问区间和:O(n)处理O(1)查询.

二. 算法解释

差分数组定义:记录当前位置的数与上一位置的数的差值. 

我们发现差分数组的前缀和s[i]就是原数组a[i]的值

差分数组的前缀和:9  3  5  4   2

现在对原数组a进行区间操作:

我们可以发现图中对新的差分数组进行前缀和的数组(即图中的新的a数组)和对原数组a进行区间操作后的数组a一模一样

另外,可以通过图中新的前缀和数组(假设为sum) 求出  区间操作后的数组a的区间和

beforesum(a~b)=sum[b]-sum[a-1];

三.关键代码

简化版:

解释版:

#include<iostream>
#include<string.h>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 100005
int main()
{
    int a[N],b[N];
    int n;//数组a的长度
    cout<<"请输入数组a的长度:"<<endl;
    cin>>n;
    cout<<"请输入数组a的元素:"<<endl;
    for(int i=1;i<=n;i++)
        cin>>a[i];

    memset(b,0,sizeof(b));
    a[0]=0;//很重要
    for(int i=1;i<=n;i++)//差分数组就是原数组前后数的差值
        b[i]=a[i]-a[i-1];

    cout<<"差分数组:"<<endl;
     for(int i=1;i<=n;i++)
        cout<<b[i]<<" ";
     cout<<endl<<endl;

    int m;//区间修改操作的组数
    cout<<"请输入需进行区间修改操作的组数:"<<endl;
    cin>>m;
    while(m--)
    {
        int l,r,x;//被区间修改的左边界与右边界  x为增加的值
        cout<<"请输入需进行区间修改操作的的左边界与右边界以及要增加的值:"<<endl;
        cin>>l>>r>>x;
        b[l]+=x;
        b[r+1]-=x;
    }

    cout<<"区间修改操作后的差分数组:"<<endl;
     for(int i=1;i<=n;i++)
        cout<<b[i]<<" ";
     cout<<endl<<endl;

    int a1[N];
    memset(a1,0,sizeof(a1));
    for(int i=1;i<=N;i++)
        a1[i]+=a1[i-1]+b[i];

    cout<<"区间修改操作后的差分数组的前缀数组(也即原数组进行区间修改后的更改数组):"<<endl;
     for(int i=1;i<=n;i++)
        cout<<a1[i]<<" ";
     cout<<endl<<endl;

     int sum[N];
     memset(sum,0,sizeof(sum));
     for(int i=1;i<=N;i++)
        sum[i]=sum[i-1]+a1[i];

    cout<<"修改后的数组的区间和数组"<<endl;
     for(int i=1;i<=n;i++)
        cout<<sum[i]<<" ";
    cout<<endl<<endl;

    cout<<"请输入需进行区间和查询操作的组数:"<<endl;
    int t;//区间和查询操作的组数
    cin>>t;
    while(t--){
        int l,r;
        cout<<"请输入需进行区间和查询操作的左右边界:"<<endl;
        cin>>l>>r;
        cout<<"该查询区间的区间和:"<<sum[r]-sum[l-1]<<endl;
    }
}
样例一:
5
9 3 5 4 2
1
2 5 5
1
2 5
样例二:
5
9 3 5 4 2
1
2 4 5
1
2 4

四.例题

借教室:https://ac.nowcoder.com/acm/problem/16564

思路:该题对时间复杂度要求很高,一般的写法都会被卡

用线段树或者差分数组进行区间修改,每个区间修改操作都是O(1)

然后用二分找答案(求需求存在问题时申请人的编号)l=1,r=m

Judge()函数判断前mid个申请人是否会存在问题(前mid个申请人的需求是否不超过可供应值)

需求数组b(1~n):前mid个申请人在第i天的总需求量

memset(b,0,sizeof(b));

for(int i=1;i<=mid;i++)//mid个申请人

{

for(int j=s[i];j<=t[i];j++)//s[i]到t[i]天每天的需求   区间修改

b[j]+=d[i];//第j天的需求为mid个申请人在该天的需求

}

这种写法绝对会超时间复杂度,所以我们采用差分数组来进行区间修改:

由于需求数组开始的值就全为0,它的差分数组也是为0,所以我们就省略求差分数组的那步,直接进行区间修改。

memset(b,0,sizeof(b));

for(int i=1;i<=mid;i++)//mid个申请人

{

b[s[i]]+=d[i];

b[t[i]+1]-=d[i];

}

 1 #include<iostream>
 2 #include<string.h>
 3 #include<cstring>
 4 #include<cstdio>
 5 using namespace std;
 6 //思路:二分+差分数组
 7 int n;
 8 int f[1000005],sum1[1000005],r[1000005],d[1000005],s[1000005],t[1000005];
 9 int Judge(int mid){
10     memset(f,0,sizeof(f));
11     for(int i=1;i<=mid;i++){//差分数组   多组区间修改
12         f[s[i]]+=d[i];
13         f[t[i]+1]-=d[i];
14     }
15     sum1[0]=0;
16     for(int i=1;i<=n;i++)
17     {
18         sum1[i]=sum1[i-1]+f[i];
19         if(sum1[i]>r[i])//说明需求比实际可供应大  申请存在问题
20         return 0;//说明小了
21     }
22     return 1;
23  }
24 int main()
25 {
26     int m;
27     while(~scanf("%d%d",&n,&m))
28     {
29         r[0]=0;
30         for(int i=1;i<=n;i++)
31         {
32             scanf("%d",&r[i]);
33         }
34         for(int j=1;j<=m;j++)
35         {
36             scanf("%d%d%d",&d[j],&s[j],&t[j]);
37
38         }
39         if(Judge(m))
40             printf("0\n");
41         else{
42         int l=1,r=m,mid,ans=0;
43         while(l<=r){
44            mid=(l+r)/2;
45             if(Judge(mid)==0)//答案就是求需求存在问题时申请人的编号
46             {
47                 r=mid-1;
48                 ans=mid;
49             }
50             else
51                 l=mid+1;
52         }
53         printf("-1\n");
54         printf("%d\n",ans);
55         }
56     }
57 }

原文地址:https://www.cnblogs.com/Aiahtwo/p/11083547.html

时间: 2024-08-30 14:24:46

数据结构之差分数组的相关文章

差分数组 and 树上差分

差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易发现的是,\(\sum_{j=1}^{i} b_j\)即代表\(a_i\) 的值. \((\sum\) 即代表累加.) 思想 看到前面的\(\sum\) 你一定会发现这是前缀和! 那你认为这是前缀和? 的确是qwq. 实际上这并不是真正意义上的前缀和. 前缀和的思想是 根据元素与元素之间的并集关系(

数据结构——树状数组

我们今天来讲一个应用比较广泛的数据结构——树状数组 它可以在O(nlogn)的复杂度下进行单点修改区间查询,下面我会分成三个模块对树状数组进行详细的解说,分别是树状数组基本操作.树状数组区间修改单点查询的实现.树状数组查询最值的实现 一. 树状数组一般分为三种操作,初始化.修改.查询 在讲基本操作之前,我们先来看一张图 这张图就是树状数组的存储方式,对于没有接触过树状数组的人来说看懂上面这张图可能有些困难,上图的A数组就是我们的原数组,C数组则是我们需要维护的数组,这样存储能干什么呢,比如我们在

SDUT 3347 数据结构实验之数组三:快速转置

数据结构实验之数组三:快速转置 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 转置运算是一种最简单的矩阵运算,对于一个m*n的矩阵M( 1 = < m < = 10000,1 = < n < = 10000 ),它的转置矩阵T是一个n*m的矩阵,且T( i , j )=M( j , i ).显然,一个稀疏矩阵的转置仍然是稀疏矩阵.你的任务是对给定一个m*n的稀疏矩阵( m

(2)redis的基本数据结构是动态数组

redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; char data[0]; }; 这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势: 1.不需要初始化,数组名直接就是所在的偏移   2.不占任何空间,指针需要占用int长度空间,空数组不占任何空间.  这个数组不占用任何内存,意味着这样的结构节省空间: 该数组的内存地址就和他后面的元素的地址相同,意味着无需初始化,数组名就是后面元素的地

【算法与数据结构】图 -- 数组表示法

图的数组表示法 借助一个二维数组表示图,该二维数组的第i行,第j列的值表示从Node[i]到Node[j]: 无向图(网):是否有边 / 权值,arr[i][j] == arr[j][i],无向图(网)的特性,矩阵关于对角线对称. 有向图(网):是否有弧 / 权值. //图的数组表示法 //最大顶点个数 const int MAX_VERTEX = 100; //最大值 const int MAX_VALUE = (1 << 31) - 1; typedef struct _tagArcCel

HDU-1556 Color the ball 【差分数组】

Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色.但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗? Input 每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <=

当数据结构遇到编程语言——数组

赵振江 数据结构 数组 一维数组 "数组"你真的很了解吗? 数组大家都不是很陌生,它已经"植入"了许多编程语言,但初学者一提到数组,可能不会联想到"数据结构",而是想到的会是一种"数据类型",数组本质上就是一种极其简单的数据结构.所谓数组,就是相同数据类型的元素按一定顺序排列的集合.也就是在内存中划分一段连续的且大小固定(注意是连续)的内存空间(或者其他存储器)保存相同数据类型的数据,如下图.一般说的简单数组,都是静态的数组,

[NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去.显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰. 为了鼓励科技创新,L国国王同意小P的物流

差分数组

介绍: 区间修改查询问题一般会想到用线段树或者树状数组来做,但是题目是离线查询,即完成修改后再查询的话,可以用到差分数组. 差分数组: 对于数组a[i],我们令d[i]=a[i]-a[i-1]  (特殊的,第一个为d[1]=a[1]),则d[i]为一个差分数组. 我们发现统计d数组的前缀和sum数组,有 sum[i]=d[1]+d[2]+d[3]+...+d[i]=a[1]+a[2]-a[1]+a[3]-a[2]+...+a[i]-a[i-1]=a[i],即前缀和sum[i]=a[i]: 因此每