区间修改的离线查询——差分数组

差分数组这样的优化表示方法(在我们日常生活中)十分常见

如果我们假设有一列数a[1],a[2],a[3]...

那么若这样的差分数组表示为d[1],d[2],d[3]...

则有d[1]=a[1]; //一般我们也可以假设一个a[0]=0,就可以和下面的一样了

d[2]=a[2]-a[1];

d[3]=a[3]-a[2];

...

差分数组应用很多,不过大部分都需要具体题目具体分析

但是在区间修改的离线查询中,差分数组是一个很优秀的线性算法

E.G. 题目描述链接

宾馆房间 hotelroom (这里题目描述我就简略了写了)

2180年奥运会竞技类分会场,将在XX市举行。会场自然是政府的事情,我们就别操心了。艾瑞克却被兴奋而苦恼的情绪折磨着,他的宾馆是XX市最好的宾馆,近期旅客投宿的订单m份接踵而至,时间从1~n天,这代表着大把大把的银子,可是他最多只能提供k间客房,更多的他只能提前去租附近的房子并赶紧装修一下,时间很紧啊。

艾瑞克找到了他最好的朋友你:“哪,这是所有的订单,你给我在1s内计算出最高峰时,超出多少间客房,这样我才能知道得去租多少房子啊。”

每张订单包含dj,sj,tj:表示从第sj日至第tj日,预定房间dj间。

【输入描述】:

第一行包含两个正整数n,m,k,表示天数、订单的数量,和现有客房数。
接下来有m行,每行包含三个正整数dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。
每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号。

【输出描述】:

只有一个整数,表示最高峰时还差多少客房,客房足够输出0(骗不到分)。

【样例输入】:

4 3 6
2 1 3
3 2 4
4 2 4

【样例输出】

3

【数据范围及描述】:

1<=n,m<=1000,000;1<=sj<=tj<=n;1<=k,dj<=1000

下面讲解原理:

(1)
我们设sum[i]为d[i]的前缀和

那么显然sun[i]=a[i]

(2)
在区间修改的时候如果我们直接对整个区间进行操作,那么复杂度将会非常高

当然我们可以使用线段树等工具来优化,但是还是很慢

那如果有机会每一次修改的时候都只改单个数据(或两个数据),那该有多好?

所以,如果我们需要在[l,r]中都加上x的话

只需要d[l]+=x,d[r+1]-=x; //(自己想想为什么)

然后这道题就迎刃而解了

我们只需要每一次修改时对d数组处理两次,然后最后查询的时候先用d[]把a[]算出来,最后直接离线O(1)查询

代码片段:

    for(int i=1;i<=m;i++){
    d=read();s=read();j=read();
    a[s]+=d;a[j+1]-=d;
    }
    for(int i=1;i<=n;i++){
    sum+=a[i];
        ans=max(ans,sum-k);
    }
    printf("%d",ans);

//还有就是稍微注意一下读入优化,这种题目当心一点

That‘s all.

原文地址:https://www.cnblogs.com/battlin/p/12243063.html

时间: 2024-10-10 05:54:53

区间修改的离线查询——差分数组的相关文章

Libre OJ 130、131、132 (树状数组 单点修改、区间查询 -&gt; 区间修改,单点查询 -&gt; 区间修改,区间查询)

#130. 树状数组 1 :单点修改,区间查询 题目链接:https://loj.ac/problem/130 题目描述 这是一道模板题. 给定数列 a[1], a[2], \dots, a[n]a[1],a[2],…,a[n],你需要依次进行 qq 个操作,操作有两类: 1 i x:给定 i,xi,x,将 a[i]a[i] 加上 xx: 2 l r:给定 l,rl,r,求 \sum_{i=l}^ra[i]∑i=lr?a[i] 的值(换言之,求 a[l]+a[l+1]+\dots+a[r]a[l

树状数组的区间修改与单点查询与区间查询

如何将普通树状数组升级 普通的单点修改单点查询就不讲了,从区间修改和单点查询讲起. 原来的值存在a[]里面,多建立个数组c1[],注意:c1[i]=a[i]-a[i-1]. 那么求a[i]的值的时候a[i]=a[i-1]+c1[i]=a[i-2]+c1[i]+c1[i-1]=-..=c1[1]+c1[2]+-+c1[i]. 所以就用c1[]建立树状数组,便可以很快查询a[i]的值.不多说,见代码. #include<iostream> #include<cstdio> #defin

关于树状数组的区间修改和单点查询

写在前面 之前一直不知道树状数组可以支持区间修改,所以写一篇博客记录一下. 首先给个小栗子: 如下图: 利用差分的思路,就得到下图: 那么如果我们要求将2~4的所有元素+2呢?我们就可以得到下图: 可以发现,差分的第二项和第五项一个加了2,一个减了2,所以对于每次区间[l,r]操作,我们只需要在l和r+1的位置加.减操作值即可,证明也很简单,首先操作区间内的数的差肯定不会变,所以区间内的一段相同,因为第一项增加了一个值k,所以他与前面一项的差就增加了k,最后一项增加了k,最后一项的后一项与最后一

线段树 区间修改,单点查询

https://www.luogu.com.cn/problem/P3368 上代码,对比一下可以发现,区间修改单点查询   和    单点修改区间查询   的add函数和search函数刚好是反的 #include<bits/stdc++.h> #define N 500005 #define endl '\n' #define _for(i,a,b) for(int i=a;i<b;i++) using namespace std; typedef long long ll; str

线段树单点修改、区间修改、单点查询值、区间查询最大值、最小值、区间和之模板

毕生所学. 1 const int N = 2e5 + 10; 2 #define lson rt << 1 // == rt * 2 左儿子 3 #define rson rt << 1 | 1 // == rt * 2 + 1 右儿子 4 #define int_mid int mid = tree[rt].l + tree[rt].r >> 1 5 int a[N]; // 初始值 6 struct node { 7 int l, r; 8 ll val, laz

HDU1556 color the ball(区间修改,单点查询)

#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <cstdio> #define MAXN 100005 int c[MAXN]; int lowbit(int x) { return x&(-x); } void upda

区间修改、单点查询

Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 29305    Accepted Submission(s): 14264 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"

bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroot: 考虑颜色数,把一条实边变成虚边,子树+1,虚变实子树-1: 但有换根操作,怎么维护子树? 也可以用 dfs 序线段树维护,其实换 rt 只是 splay 的根方向改变,对应的子树还是可以找到的: 注意虚边变实或实边变虚时要找子树,不是直接找那个儿子,而是找那个儿子所在 splay 的根: 然后

数据结构之差分数组

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)查询. 二. 算法解释 差分数组定义:记录当前位置的数与上一位置的数的差值.  我