【DS】浅谈树状数组倍增

无意中看到的一个小 trick,便记录下来。

引入

给您一个数组,您需要实现以下操作和询问:

插入一个数字 x

查询排名为 k 的数 x

显然我们有权值线段树或者平衡树的做法。
但是我偏不(傲娇),我们来考虑树状数组怎么做。

树状数组倍增

定义:

n:数组大小

ai:离散化后第 i 个数出现的次数

ci:树状数组

思路

插入一个数字就是单点修改啦,考虑询问。

写过平衡树模板的我们肯定知道,一个数 x (离散化后)的排名就是比 x 小的数的个数 +1,即 rank(x)=(i=1x1ai)+1 。那么反过来,要查询排名为 k 的数 x, 它的位置就是 maxrank(x)kx,我们把它展开来看,即

(i=1x1ai)+1k

(i=1x1ai)k1

左半部分可以直接树状数组求,我们枚举一个 r,那么我们枚举到的符合条件的最大的 r 就是 (x1),答案即为 r+1

为什么不能直接 k?因为有的数可能不存在,例如 a={1,0,1,0,0} ,我们查询排名为 2 的数,按正确的方法答案就是 3,如果直接 k 则输出为 5。不过有的时候我们会需要这样做,在后文会讲到。

如何求 r?显然不能 O(nlogn),那有没有什么方法能降低枚举复杂度至 O(logn) 呢?

废话,看标题不就知道了

具体实现

引理

ci=j=ilowbit(i)+1iai

由树状数组的定义知显然。

倍增

我们能不能通过枚举跳 2logn,2logn1,...,21,20 的距离去找呢?

代码如下:

int kth(int k){
    int r=0,tot=0,x,y;
    for(int i=log(值域);~i;--i){
        x=r+(1<<i);if(x>值域)continue;
        y=tot+c[x];
        if(y<k)r=x,tot=y;
    }
    return r+1;
}

这里每次 tottot+cr+2i 是什么意思呢?根据上面得引理可知,加上 cr+2i 相当于加上 j=rr+2iai,即不断地向后拓展,到最后 tot 的值即为 i=1rai

为什么这样就能满足 r 最大?因为我们是从大到小枚举的。

优点 & 缺点

优点:常数小,码量小,容易记。

缺点:需要离线。

用途

一般用于优化部分需要求 k 小的操作,不作为主要算法。

例题

CF786C Till I Collapse

题意:将 n 个数划分成 m 段使得每中不同数字的个数 k,对于每个 k 满足 1kn ,求出最小的 m

考虑对于一个 k 怎么求。我们贪心地尽可能分最大的段,使得段内不同数字个数不大于 k,询问区间不同数字的个数,就是数颜色嘛,我们想到 HH 的项链 的做法,但是有点不同:对于 HH 的项链里,我们知道右端点的位置,于是对于每一个数字的贡献都放到尽可能右边;但是这道题里面我们并不知道右端点(而是要求它),所以对于每一个枚举到的左端点的数字,(如果它对答案有贡献)我们计算贡献之后将它的贡献放到下一个出现的位置上就行了。每一次分段询问最远能到达的右端点即可,我们有这样的代码:

void add(int x,int v){while(x<=n)c[x]+=v,x+=lb;}
int kth(int k){
    int r=0,tot=0,x,y;
    ++k;//注意这里 k 要加一
    for(int i=18;~i;--i){
        x=r+(1<<i);if(x>n)continue;
        y=tot+c[x];
        if(y<k)r=x,tot=y;
    }
    return r;//注意这里 r 不用加一
}

for(int l=1,r=0;l<=n;++l){
    if(l==r+1)++ans,r=kth(l);
    add(l,-1),add(nxt[l],1);
}

为什么 k 要加一而 r 不用加一?因为我们计算数字个数的时候,中间可能有一串 0,例如:a={1,1,0,1,0,0,1,0}k=3。如果是之前的代码的话,返回的答案是 4,而实际上能扩展到的最远的右端点是 6。我们把 k 加一并且 r 不加一就可避免此问题。

对于 1n 的所有 k 怎么求?我们可以一起求啊!毕竟每个数的贡献仅在数本身,我们对于所有询问的左端点维护个优先队列,然后按照上面的方法计算答案即可。

提交记录

其他练习:

CF1181D Irrigation

Luogu P6619 [省选联考 2020 A/B 卷] 冰火战士

posted @   RuntimeErr  阅读(707)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示