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

差分数组这样的优化表示方法十分常见

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

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

  • 则有d[1]=a[1];

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

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

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

...

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

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

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.

posted @ 2020-01-30 16:34  battlin  阅读(239)  评论(0编辑  收藏  举报