可持久化线段树
假设我们需要一棵线段树,它要在可以维护普通线段树的操作的同时还可以查询历史版本。
最zz的做法当然是建出\(m\)棵线段树,时间和空间开销都是爆炸的,但是我们可以通过每次尽可能使用原来的结点来使复杂度降为\(O(nlogn)\)

这样每次对于需要更改的结点,直接新建一个,而不是修改原来的结点,再储存一下每次的树根就可以了。
代码:
int update(int k,int l,int r,int x) //将位置x上的元素+1,返回新的树根
{
int ind=++size;T[ind]=T[k];++T[ind].val; //新建节点
if (l==r) return ind;
int mid=(l+r)>>1;
if (x<=mid)
T[ind].l=update(T[k].l,l,mid,x);
else
T[ind].r=update(T[k].r,mid+1,r,x);
return ind;
}
查找同普通线段树。
主席树:
我们考虑这样一棵可持久化线段树:对于长度为\(n\)的数组A,我们每次将位置为A[i]的元素数量+1(即第\(i\)棵树的区间\([l,r]\)维护的是数组A[1...i]中值在\([l,r]\)的个数,预处理复杂度是\(O(nlogn)\)的,这样我们就可以用T[r]-T[l-1]来求得数组A[l,r]的值出现在一区间的个数,这在求第K大元素等问题上有很大帮助。

浙公网安备 33010602011771号