zoukankan      html  css  js  c++  java
  • 【树状数组·进阶篇】树状数组实现平衡树(树状数组上二分)

    (Preface)

    余未曾想到,树状数组居然是一个这么高端的东西。

    从未想到过树状数组上还可以二分,从未想到过树状数组还能实现平衡树的功能。

    唔姆,树状数组果然也是美丽的,余喜欢一切美丽的东西。

    树状数组上二分

    众所周知,树状数组上的(a_i)维护的是(sum_{k=i-lowbit(i)+1}^ival_k)

    考虑强行令树状数组的大小为(2)的幂

    每次二分边界([l,r]),中点就是(mid)

    然后就会发现,因为树状数组大小是(2)的幂,每次二分其实就相当于在判断二进制下某一位是否能填作(1)

    因此,(a_{mid})的值实际上就等于(sum_{k=l}^{mid}val_k)

    唔姆,假设树状数组的(val_i)表示等于(i)的数的个数,那么(a_{mid})的值等同于值在([l,mid])范围内的数的个数。

    于是就能轻松实现第(k)大的询问了。

    模板:普通平衡树

    其实只要能够求第(k)大,平衡树的其他操作都非常简单了,前驱/后继都可以转化为询问排名再询问第(k)大的操作。

    唯一一个特殊注意点,就是由于这道题中值可能为负,需要把每个数都加上(10^7)再操作。

    代码(class)封装,码风毒瘤(尽管在这道题中体现不多)。

    /*友情提醒:I表示inline,可忽略;RI表示register int,CI表示const int&,可以直接视作int;W表示while*/
    class TreeArray//树状数组实现平衡树 
    {
    	private:
    		#define V (1<<25)//V存储总值域,必须为2的幂 
    		#define P 10000000//因为存在负数,所有数据都要加上P
    		int a[V+5];I void U(RI x,CI v) {W(x<=V) a[x]+=v,x+=x&-x;}//后缀修改 
    		I int Q(RI x,RI t=0) {W(x) t+=a[x],x-=x&-x;return t;}//求前缀和(小于等于x的数的个数) 
    	public:
    		I int Kth(RI k) {RI l=1,r=V,mid;W(l^r) a[mid=l+r>>1]<k?(k-=a[mid],l=mid+1):r=mid;return l-P;}//树状数组上二分询问第k大
    		I void Add(CI x) {U(x+P,1);}I void Del(CI x) {U(x+P,-1);}I int Rk(CI x) {return Q(x+P-1)+1;}//插入;删除;询问排名 
    		I int Pre(CI x) {return Kth(Q(x+P-1));}I int Nxt(CI x) {return Kth(Q(x+P)+1);}//前驱;后继 
    };
    

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

    • 有两个数组(Ice_i,Fire_i)
    • 每次操作修改某个数组中某个位置上的数。(始终非负)
    • 每次操作完求一个最大的整数(k),使得(min{sum_{ile k}Ice_i,sum_{ige k}Fire_i})最大,并求出这个最大值。
    • 操作数量(le2 imes 10^6)

    很显然,(f(k)=sum_{ile k}Ice_i)(k)增大递增,(g(k)=sum_{ige k}Fire_i)(k)增大递减。

    那么根据初中函数知识就可以知道,要使最小值最大,就是求两个函数的交点。

    题目很简单,可惜这道题居然卡线段树!

    这时候就要请出树状数组上二分啦!

    每次先二分出最大的(k)满足(f(k)<g(k)),由于(k)是整数因此不一定能找到交点,还要比较(f(k))(g(k+1))谁更大。

    求出最大值之后,还要再次树状数组上二分求出最大的(k)

    大致思路差不多就这样啦。

    (Postscript)

    树状数组最大的优点就是代码短、常数小,因此真的真的是个非常美丽的算法哦!

  • 相关阅读:
    Direct3D轮回:游戏场景之天空
    Direct3D轮回:游戏特效之晴天光晕
    Direct3D轮回:基于.X文件的网格加载及渲染
    Direct3D轮回:游戏特效之风动、雾化
    Direct3D轮回:游戏场景之陆地
    Direct3D轮回:基于ID3DXSprite的2D元素绘制
    Direct3D轮回:基于HLSL实现D3D中的光照特效
    Direct3D轮回:构建基于Direct3D的通用摄影机类
    Direct3D轮回:构建基于DirectInput机制的键盘输入设备
    剪切上传图片源码
  • 原文地址:https://www.cnblogs.com/Nero-Claudius/p/TreeArray1.html
Copyright © 2011-2022 走看看