当前位置:首页 > 分治 > 正文
洛谷P1816忠诚
3029+

题目大意:n个数,q个询问,请依次回答第x个数到第y个数中最小那个数是多少?

题目描述

老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。

输入输出格式

输入格式:
输入中第一行有两个数m,n表示有m(m<=100000)笔账,n表示有n个问题,n<=100000。

第二行为m个数,分别是账目的钱数

后面n行分别是n个问题,每行有2个数字说明开始结束的账目编号。

输出格式:
输出文件中为每个问题的答案。具体查看样例。

输入输出样例

输入样例#1:

10 3
1 2 3 4 5 6 7 8 9 10
2 7
3 9
1 10

输出样例#1:

2 3 1

解题思路

由于n和m都很大,暴力查找每个询问的最小值,时间复杂度是O(n*m),会超时,需要一种更快的查找方法。

我们可以预先处理好以每个编号开头的长度为2^k的区间的最小值f[次方][开头],初始值f[0][i] = a[i],因为只有一个的时候最小值就是自己。有2^0可以推出2^1,进而推出2^2……预处理的时间复杂度是O(n*log2n)。

对于询问的区间,我们可以把他分成两个“有重叠”的以某个数字开头的长度相等且是2^k次方的区间,用预处理好的数据,就可以做到O(1)的回答。

程序实现

分块介绍:如果每次都扫一遍[x,y],那么询问一次的复杂度就是O(n),如果我们把这n个数分块根号n块,每块根号n个数;在读入数据的时候,我们可以预处理每一块的最小值;对于每个询问,如果他区间很小(不包含一整块),那么逐个比较是不超时的,如果他很大,逐个比较会超时,那么他肯定跨越很大个块,我们只需要比较块的最小值即可,这样每次询问,时间复杂度是O(√n)。

每一块√n,速度加快了,其实还可以更快——我们可以把询问的每一块分成两个2^k次方小块,并预处理所有2^k块的最小值,这样每次就只需要比较一次就找到最小值。

About

坚决不Copy代码!

本文标签:,,,,,

洛谷P1816忠诚:等您坐沙发呢!

发表评论

您必须 [ 登录 ] 才能发表留言!