可持久化:
可以访问历史版本的“升级版”的数据结构,利用访问历史版本的性质,可以做到许多在区间上的操作。
可持久化线段树:
例题:
cqoi2111:区间第k大
给定一个长度为n的序列,m个询问,每个询问的形式为:l,r,k表示在[l,r]间中的第k大元素.
(n<=100000, m<=100000,1<=l<=r<=n, 1<=k<=r-l+1)
如果用线段树来储存某个区间的第i大,显然是很不好实现的。因此,我们换一个思路,我们将线段树建在值域上(需要离散化),储存某个区间存在多少个数。
每插入一个新的值,那么这个值会影响线段树上的哪些节点?
这样一来,我们就做到了保存历史版本。
具体实现,我们可以再插入新节点时,插入位置以外的半个区间的指针指向上一个版本,继续走当前这个区间,直到抵达叶节点为止。
对于这道题,求解的过程很类似于在平衡树上找第k大
如果左区间的数的个数>k,走左树
反之,走右树,并将 k-左区间的数的个数
附上我的(丑)模板
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
struct node{
int cnt;
node *ch[2];
}Seg[MAXN*20],*root[MAXN],*ncnt=Seg;
int a[MAXN],b[MAXN],bn,n,m;
void init(node *p){
p->cnt=0;
p->ch[0]=p->ch[1]=NULL;
}
void build(node *&p,int l,int r){
p=++ncnt;
init(p);
if(l+1>=r)
return ;
int mid=(l+r)>>1;
build(p->ch[0],l,mid);
build(p->ch[1],mid,r);
}
void insert(node *&x,node