权值线段树
Posted vividbingo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了权值线段树相关的知识,希望对你有一定的参考价值。
定义
权值线段树和线段树类似,只是维护的数据不一样而已。权值线段树的叶节点维护的是数据出现的次数。
为了防止数据过大,一般先离散化数据再使用权值线段树维护。
主席树的前置技能为权值线段树。
权值线段树可以解决:
①插入x数
②删除x数(若有多个相同的数,因只删除一个)
③查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
④查询排名为x的数
⑤求x的前驱(前驱定义为小于x,且最大的数)
⑥求x的后继(后继定义为大于x,且最小的数)
实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct node
{int L,R,w;}tree[maxn<<2];
int op[maxn],w[maxn];
vector<int> scatter;
void build(int L,int R,int k);
int get(int x);
void update(int L,int R,int w,int f,int k);
int rank_of_x(int L,int R,int l,int r,int k);
int rank_is_x(int L,int R,int rank,int k);
int main()
{
int i,n,N;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&op[i],&w[i]);
if(op[i]!=4) scatter.push_back(w[i]);
}
sort(scatter.begin(),scatter.end());
scatter.resize(unique(scatter.begin(),scatter.end())-scatter.begin());
N=scatter.size();build(1,N,1);
for(i=1;i<=n;i++)
{
if(op[i]==1) update(1,N,get(w[i]),1,1);
else if(op[i]==2) update(1,N,get(w[i]),-1,1);
else if(op[i]==3) printf("%d
",rank_of_x(1,N,1,get(w[i])-1,1)+1);
else if(op[i]==4) printf("%d
",scatter[rank_is_x(1,N,w[i],1)-1]);
else if(op[i]==5) printf("%d
",scatter[rank_is_x(1,N,rank_of_x(1,N,1,get(w[i])-1,1),1)-1]);
else printf("%d
",scatter[rank_is_x(1,N,rank_of_x(1,N,1,get(w[i]),1)+1,1)-1]);
}
system("pause");
return 0;
}
void build(int L,int R,int k)
{
tree[k].L=L;tree[k].R=R;
if(L==R)
{
tree[k].w=0;
return ;
}
int mid=(L+R)/2;
build(L,mid,k<<1);
build(mid+1,R,k<<1|1);
tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
int get(int x)
{return lower_bound(scatter.begin(),scatter.end(),x)-scatter.begin()+1;}
void update(int L,int R,int w,int f,int k)
{
if(L==R)
{
tree[k].w+=f;
return ;
}
int mid=(L+R)/2;
if(w<=mid) update(L,mid,w,f,k<<1);
else update(mid+1,R,w,f,k<<1|1);
tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
int rank_of_x(int L,int R,int l,int r,int k)
{
if(l>r) return 0;
if(L>=l&&R<=r) return tree[k].w;
int mid=(L+R)/2,ans=0;
if(l<=mid) ans+=rank_of_x(L,mid,l,r,k<<1);
if(r>mid) ans+=rank_of_x(mid+1,R,l,r,k<<1|1);
return ans;
}
int rank_is_x(int L,int R,int rank,int k)
{
if(L==R) return R;
int mid=(L+R)/2;
if(rank<=tree[k<<1].w) return rank_is_x(L,mid,rank,k<<1);
else return rank_is_x(mid+1,R,rank-tree[k<<1].w,k<<1|1);
}
以上是关于权值线段树的主要内容,如果未能解决你的问题,请参考以下文章