【小结】树状数组二分
例题:给定数列 \(a_1,a_2,\dots,a_n\),有 \(q\) 次询问,每次询问给定 \(k\),求区间第 \(k\) 小。\(1\leq n,q\leq 2\times 10^6\)。
考虑普通的树状数组+二分肯定是过不去的。因为复杂度是 \(\mathcal O(qlog^2n)\)。
所以要优化成单 log。可以考虑拆位。令 \(i\) 从 \(L-1\) 枚举到 \(0\)。其中 \(L\) 是 \(\lceil log_2n \rceil\)。然后就可以二进制拆位,对于一个可以加上的地方就加上。
假设当前的位置是 \(pos\),枚举到了 \(i\),那么 \(c_{pos+(1<<i)}\) 表示的就是 \([pos+1,pos+(1<<i)]\) 的和。直接累加进 \(pos\) 然后判断是否合法即可。
求最后一个 \(\leq k\) 的:
int Q(int k)
{
int i,pos=0,res=0;
for (i=L-1;i>=0;i--)
{
if (pos+(1<<i)<=n&&res+c[pos+(1<<i)]<=k)
{
pos+=(1<<i);
res+=c[pos];
}
}
return res;
}
求第一个 \(\geq k\) 的(\(c_{pos-2^i}\) 为左半部分,\(c_{pos}\) 为右半部分):
int Q(int k)
{
int i,pos=(1<<L),res=0;
for (i=L-1;i>=0;i--)
{
if (c[pos-(1<<i)]>=k) pos-=(1<<i);
else k-=c[pos-(1<<i)];
}
return res;
}

浙公网安备 33010602011771号