权值线段树

Posted op-z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了权值线段树相关的知识,希望对你有一定的参考价值。

权值线段树只是节点存的内容变成了权值,区间,区间和,区间数字个数等,和一般线段树的操作差别不大

但对于某些特定问题来说操作很简便,值域较大时一般会采用离散化(就只能离线了

可求区间第k大数,逆序对个数等

示例如图:

 //待添加

结构体存

struct node

    ll l, r, num;//区间范围,区间数字个数
    ll s;        //区间和
tree[N*4];      //开4倍空间

 

建树

void build(ll l, ll r, ll now)

    tree[now].l=l;
    tree[now].r=r;
    tree[now].s=0;
    tree[now].num=0;
    if(l==r)
    
        return ;
    
    ll mid=(l+r)>>1;
    build(l,mid,now<<1);
    build(mid+1,r,now<<1|1); //左右递归建树
    return ;

插入新点(根据不同问题修改

void update(ll pos, ll now) //pos为下标,b[pos]存值

    if(tree[now].l==tree[now].r)
    
        tree[now].s+=b[pos];    //更新区间和,区间数字个数
        tree[now].num++;
        return ;
    
    if(pos<=tree[now<<1].r) update(pos,now<<1);
    else update(pos,now<<1|1);
    tree[now].s=tree[now<<1].s+tree[now<<1|1].s;
    tree[now].num=tree[now<<1].num+tree[now<<1|1].num;
    return ;

 查询(根据不同问题修改

ll query(ll now, ll k) //查询求和<=k的最大个数

    if(tree[now].s<=k) return tree[now].num;
    if(tree[now].l==tree[now].r)
        return min(tree[now].num, k/b[tree[now].l]);
    if(k<=tree[now<<1].s) return query(now<<1,k);
    else return tree[now<<1].num+query(now<<1|1,k-tree[now<<1].s);

初始数据处理

for(i=1; i<=n; i++)
    sc(a[i]), b[i]=a[i];
sort(b+1,b+1+n);//需排序
build(1,unique(b+1,b+n+1)-(b+1),1);//unique去重,初始建树

ll pos=lower_bound(b+1,b+n+1,a[i])-b;//二分查找位置( -(b+1)+1=-b  )
update(pos,1);

 

以上是关于权值线段树的主要内容,如果未能解决你的问题,请参考以下文章

可持久化线段树--主席树

知识点 - 线段树 权值 树套树 二维 可持续

详解权值线段树

权值线段树套序列线段树

一般线段树与权值线段树

权值线段树