一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
Input
第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的
要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
输入保证满足条件。
第一行所谓“排过序”指的是从大到小排序!
Output
Sample Input
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
Sample Output
HINT
0:n,Q<=100
1,...,5:n<=2000
0,...,19:n<=20000,Q<=25000
题目大意:给出一列数,有q个询问,每次询问给出a,b,c,d, 意思是在[a,b]中找到一个左端点l,[c,d]中找到一个右端点r,使得[l,r]区间里的中位数最大,输出最大的中位数。题目强制在线。
对于每一次询问:我们二分答案,设当前答案为x,进行验证。我们把大于等于x的位置的贡献记为1,小于x的位置的贡献记为-1,那么只要找到一个[l,r]区间满足sum(l,r)的值>=0 (ps. 这里说的中位数感觉应该要>=1吧,因为题目里说两个数列都是0开始,除法为向下取整,并且是从大到小排序,手算一下,sum(l,r)的值应该要>0的时候才是能满足的),那么这个答案就是满足题意的,继续找是否有更大的答案,同理验证。
那么问题就转为如何找到这样的一个(l,r)区间:
我们用一个线段树来记录每个位置的贡献为1还是-1(大于等于x的贡献为1,小于的贡献为-1),那么只要看满足题意的max(sum(l,r))是否大于等于0就可以了。因为l在[a,b],r在[c,d], 那么[b,c]这个区间里的值肯定是必须要计算的,记为find_sum(b,c),然后我们找到[a,b-1]这个区间里向右对齐的最大和,记为max(find_r(a,b-1),0),[c+1,d]中向左对齐的最大和,记为max(find_l(c+1,d),0) 。(这里要取max是因为可以一个都不取,所以最小的值是0)最后判断max(sum(l,r))+max(find_r(a,b-1),0)+max(find_l(c+1,d),0)>=0是否成立。
但是这样的话需要n棵线段树(每个不同的值为基础,贡献是不同的),我们考虑简化,我们可以用可持久化线段树。先将n个数排序,再插入可持久化线段树中,因为前一个数和当前这棵树只有一个位置是不同的,所以可以用可持久化线段树来简化问题。
这样就结束了。
#include
#include