题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577
题意:由于中国庞大的人口和站台,总是出现票的问题,现在政府需要你去开发一个新的查票系统。 一个火车只能载k个乘客,并且每个乘客仅仅只能从a->b买一张票,在任何时间每辆火车载客不超过k人,一个人提前买的票将是有效的。 |
输入: 多组测试数据,第一行测试组数,接下来每组的第一行,为k(列车的承载人数),Q(几组数据);接下来Q行,每行有两个数字a和b |
输出: 每组测试数据输出三行,第一行测试组数,如果第i次查询满足题意输出从1到i,每个数字有一个空格,每组测试后有一个空行 |
解释样例:
1-> 6 已经占了两个座位,3->4在3站台可以上车,1->5由于3->4经过的站与其有重复并且3->4先买的票,所以1->5不满足条件,1->2由于之前只有两个1->6经过1->2站,所以刚好可以坐上车,2->4与1->5同理,因为与3->4有重复。所以第1,2,3,5个乘客满足条件。
线段树:
线段树是一种二叉搜索数,每一个节点都对应一定的区间,能够快速的对区间进行更新,时间复杂度比较小;
Lazy思想:(懒操作)
常运用于线段树的一个算法是lazy思想,lazy思想是说若更新的区间已经完全包含区间s,将s区间标记,暂不向下更新,若下一次的更新或询问需要用的已经标记过的区间的子区间,再将标记过的区间进行向下更新,并且取消对区间s的标记,增加对区间两个左右子树的标记。若一直未询问到,则不向下更新。通过这种方式可以达到节约时间的目的。
举个简单粗暴的例子:
对应下面的那个图,假如目的是求和,现在要给[1,6] 的值都加2,那么我们从[1,12]->[1,6],然后[1,6]的sum值加上区间长度[ (6-1+1)*2 ],再把[1,6]的add[i]设置为2,就不再往下更新了【这里极大提高效率】。下一次更新/查询[1,6]的子区间时,我们将[1,6]原存的add值下传给[1,6]的两个直接子区间,再往下更新。假设在这种情况下,我们再更新[1,6]加3,则[1,6]的add值为2+3=5,然后我们查询[1,3],则从上往下经过[1,6]时把[1,6]的add值给了子区间[1,3]和[4,6],同时把sum[子区间]跟着子区间长度和add[父结点]改动,清除add[父节点]。【如果是查询间接子区间,则连续传递add值,也就是连续pushDown】
详细例子:
假设update()是区间改值,query()是求和,所有叶子区间的和都为1,则[7,8]和[7,9]在build()的时候就附上了值(图中绿色字体)。假设此时我们更新[7,9]的值,改为2,则线段树从[1,12]->[7,12]->[7,9],然后把[7,9]打上值为2的标记,求和(求和直接用区间长度*此时更新的值),然后不去更新[7,8]和[9,9]了,他们值仍然是2和1,lazy值为0。

#include
#include
#include
#include