权值线段树

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

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

可求区间第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);
原文地址:https://www.cnblogs.com/op-z/p/11272713.html