【小结】树状数组二分

例题:给定数列 \(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;
}
posted @ 2026-08-21 16:43  GUO120822  阅读(2)  评论(0)    收藏  举报