NOIP--OI省选算法之主席树
主席树是什么
主席树:是一种前缀树,通过一个地址root[i]−>root[i−1]来实现的;
建树
如上图所示,我们在插入元素的时候分别为每一个元素都给它建一个树
void init(int &p,int l,int r){
p=++tot;
T[p].v=0; if(l==r)return;
int mid=l+r>>1;
init(T[p].l,l,mid);
init(T[p].r,mid+1,r);
} void insert(int &p,int l,int r,int x,int pre){
p=++tot;
T[p]=T[pre];//继承上一个树的信息(像前缀和一样)
T[p].v++;//加上本节点的信息
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)insert(T[p].l,l,mid,x,T[pre].l);
else insert(T[p].r,mid+1,r,x,T[pre].r);
}
查询
由于主席树为前缀树,故我们可以通过查询不同时期的树来搜集信息做到多维护一维信息的效果
int query(int root1,int root2,int l,int r,int k){
if(l==r)return l; //由于这是一个前缀树,我们通过把id1,id2
int v1=T[T[root1].r].v;
int v2=T[T[root2].r].v; //搜集两个时期的信息
int v=v2-v1,mid=l+r>>1;
if(k<=v)return query(T[root1].r,T[root2].r,mid+1,r,k);
return query(T[root1].l,T[root2].l,l,mid,k-v);
}
综上
struct Tree{
struct node{int l,r,v;}T[M<<4];
void init(int &p,int l,int r){
p=++tot;
T[p].v=0;
if(l==r)return;
int mid=l+r>>1;
init(T[p].l,l,mid);
init(T[p].r,mid+1,r);
} void insert(int &p,int l,int r,int x,int pre){
p=++tot;
T[p]=T[pre];//继承上一个树的信息(先前缀和一样)
T[p].v++;//加上本节点的信息
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)insert(T[p].l,l,mid,x,T[pre].l);
else insert(T[p].r,mid+1,r,x,T[pre].r);
} int query(int id1,int id2,int l,int r,int k){ if(l==r)return l; //由于这是一个前缀树,我们通过把id1,id2
int v1=T[T[id1].r].v;//
int v2=T[T[id2].r].v;
int v=v2-v1,mid=l+r>>1;
if(k<=v)return query(T[id1].r,T[id2].r,mid+1,r,k);
return query(T[id1].l,T[id2].l,l,mid,k-v);
}
}CT;
NOIP信息学视频地址
视频地址
链接:https://pan.baidu.com/s/1tHo1DFMaDuMZAemNH60dmw
提取码:7jgr