(我们永远的)大哥有很多的小弟(n个)。每一个小弟有一个智力值。现在小弟们聚集在了大哥身旁,排成了一队,等待大哥的检阅。n个小弟的智力值是一个1到n的排列。
大哥在检阅小弟时,每次会选择一些相邻的小弟,让他们按照自己的智力值从小到大或从大到小顺序重新排队(没有被选择的小弟位置不变),以便他排除其中的二五仔。
在大哥检阅完小弟之后,老仙突然来了。他十分想为难一下大哥,所以他问大哥其中某一个小弟的智力值是多少。大哥十分的慌,并不能回答这个问题,所以让你来帮他解决这个问题。如果你能够解决,大哥可能会赠与你守护者的三叉戟和并教你他的换家绝学。
输入
第一行3个整数n,q,k,表示小弟的数目,大哥检阅小弟时让一些小弟重新排队的次数,以及最后老仙问他的是第几个小弟的智力值。
第二行n(1≤n≤10^5105)个整数,表示每个小弟的智力值,保证符合题意,是1到n的一个排列。
接下来q(1≤q≤10^5105)行,每行3个整数a,b,t(1≤a≤b≤n,0≤t≤1),表示他选择了第a个到第b个小弟(a,b均包含)进行重新排列。若t=0,则为从小到大;若t=1,则为从大到小。
输出
输出一个整数,代表在检阅之后第k个小弟的智力值是多少。
输出时每行末尾的多余空格,不影响答案正确性
样例输入
5 2 4
1 4 3 2 5
1 3 0
3 5 1
样例输出
4
题目来源
ACM训练联盟周赛
题目意思:
先给你你个序列,然后又q次操作,对l 到 r区间排序,有升序和降序两种排序,最后询问序列下标为k的地方的值。
涉及到区间,所以用线段树可以优化时间,但是这道题有点难,不好和线段树扯上关系。
因为我们只查询一个数,所以我们创建一个数组,比m大的全部置为1,小的置为0(这个m其实是二分的m,后面具体解释)
区间置为1和区间置为0就可以很好的利用线段树。
线段树的点存的是区间内1的个数(比m大的数的个数)
总的来说,就是枚举答案,模拟一下排序,大致的判断答案的范围,不断缩小范围,应用到线段树就是在模拟排序中。
算法步骤:
①二分法边界 l = 1,r = n,middle = (l+r)>>1;然后根据middle的值建线段树,把单点值大于middle的置为1,小于middle置为0,这样做的原因是:我们假设答案就是middle,那么大于middle的我们置1,小于middle置0,就能把它们分成两类,最后就便于线段树操作.
eg: 1 4 3 2 的数组 l = 1,r = 4,middle = 2,所以我们把数组中大于2的那个位置下标对应在线段树中置1,即线段树2-2区间置为1, 3-3区间置为1,得到:0 1 1 0,然后执行下一步。
②模拟排序操作,我们只需要先求出排序区间里面有多少个1,假设有t个,然后将前t个置为1,排序区间剩下的置为0就可以了,这是降序,对于升序也是类似
eg:我们接着①中的例子,我们已经把数组变成 0 1 1 0,假设我们需要1-4排降序,我们只需要把数组改成1 1 0 0就行了,这样是显然可以用线段树进行操作的,通过这样,我们就模拟了排序,最后我们求k处的值时,只需要询问k点值就行了,那么在这里,它只可能是0或1,0代表比middle小,1表示比middle大。
③执行排序操作后进行判断,即更新二分法l和r的值,判断的依据是查询线段树第k个点的数值,如果是1,说明比middle大,所以答案应该继续往上找,往middle--r找,如果是0,则应该往下找,这也是理解这个题目的关键。
拿样例来举例吧,解释一下③
5 2 4
1 4 3 2 5
1 3 0
3 5 1
执行①
l = 1,r = 5
middle = 3
先是建树,建树完后,1 4 3 2 5 对于线段树的点为 0 1 0 0 1 大于middle的地方置1
执行②
1--3升序排序 得到 1 0 0 0 1,对应线段树操作是,先查询到1---3中有1个1,所以1---3中前一个置1,后两个置0;
3---5降序排序,得到1 0 1 0 0,对应线段树操作是,先查询3---5中有1个1,所以1---3中前一个置1,后两个置0;
执行③
k= 2在线段树中值为0,所以排序之后k出的值是大于middle = 3的,所以我们可以缩小区间。
然后循环条件是l 执行②,两次排序最后的结果为 0 0 1 0 0 执行③ k = 2的地方是0,所以排序之后的k处值是比middle = 4小的(或者等于),所以缩小区间为 4-4,不满足了l 上述构造的01序列只是为了理解方便,实际上还是要对应到线段树的每个点上去。 然后需要注意的细节是,对于标记数组,最好开始初始值设为-1,如果有置1的操作,标记数组就1,置0的操作,标记数组就0. 这样可以算一下复杂度为,可以解决。 然后线段树的写法大家适应下,每个人风格都不一样。 #include