权值线段树
layout: post
title: 权值线段树
subtitle: 线段树的特殊运用,可以称之为小小平衡树
categories: 数据结构
tags: [线段树]
顾名思义,维护权值的线段树。在一定情况下可以代替平衡树使用。
原理是用线段树维护桶,节点维护子树中数的个数。所以空间开销与数据的值域相关。
那要是值域过大怎么办:离散化和动态开点,离散化可以将数据值域缩小到数据数量,将空间复杂度变为 \(O(n)\),缺点是需要离线。而需要在线则需支持动态开点,即用多少开多少。
权值线段树:支持平衡树操作(翻转除外),并附带离散化
P3369普通平衡树
#include
using namespace std;
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
#define LL long long
#define N 100010
struct node_val_tree
{
int l,r,mid;
int d;
};
struct val_tree
{
node_val_tree t[4*N];
void build(int i,int l,int r)
{
t[i].l=l;t[i].r=r;t[i].mid=(l+r)>>1;
t[i].d=0;
if(l==r) return;
build(i<<1,l,t[i].mid);
build(i<<1|1,t[i].mid+1,r);
return;
}
void insert(int i,int l,int k)
{
if(l==t[i].l&&t[i].r==l)
{
if(t[i].d+k>=0)t[i].d+=k;
return;
}
if(l<=t[i].mid) insert(i<<1,l,k);
if(t[i].mid+1<=l) insert(i<<1|1,l,k);
t[i].d=(t[i<<1].d+t[i<<1|1].d);
return;
}
int kth(int i,int k)
{
if(t[i].l==t[i].r)
{
return t[i].l;
}
int res=0;
if(k<=t[i<<1].d) res+=kth(i<<1,k);
if(t[i<<1].d+1<=k) res+=kth(i<<1|1,k-t[i<<1].d);
return res;
}
int query(int i,int l,int r)
{
if(l>r) return 0;
if(l<=t[i].l&&t[i].r<=r)
{
return t[i].d;
}
int res=0;
if(l<=t[i].mid) res+=query(i<<1,l,r);
if(t[i].mid+1<=r) res+=query(i<<1|1,l,r);
return res;
}
int rk(int k)
{
return query(1,1,k-1)+1;
}
int pre(int k)
{
return kth(1,rk(k)-1);
}
int nxt(int k)
{
return kth(1,rk(k+1));
}
}t;
int n,opt[N],x[N];
int b[N],id[N],tot;
int c[N];
bool cmp_val(int xxx,int yyy)
{
return b[xxx]