可持久化学习笔记合集

本来只想着学下可持久化并查集但是感觉这个知识点也没有很难专门开一篇博客不至于,,,所以就一块儿写了$QwQ$

可持久化线段树

$umm$因为这个是很久以前就会了的知识点所以只记下基本的想法$QwQ$

就考虑因为每次改动的节点并不多,所以不需要改变的节点就直接继承历史记录就成,然后要改变的就改下,就欧克了

然后因为作为主席树形态就不像线段树的形态那么优美了所以并没有什么左儿子就是乘二右二子就是乘二加一的说法,所以要记录下左右儿子

然后就和线段树麻油区别了鸭?$over$

放下例题对应的代码趴$QwQ$

(因为是很古早的代码了所以有些细节和我现在的不太一样,,,但核心思想是一样的能理解就成$QwQ$

(然后有一个点还是想说下,就这个$build$,除了耗空间以外没有任何意义,,,所以我现在都不用了$QwQ$

#include
using namespace std;
#define il inline
#define fr first
#define sc second
#define rg register
#define gc getchar()
#define mp make_pair
#define ll long long
#define t(i) edge[i].to
#define rp(i,x,y) for(rg ll i=x;i<=y;++i)
#define my(i,x,y) for(rg ll i=x;i>=y;--i)
#define e(i,x) for(rg ll i=head[x];i;i=edge[i].nxt)

const ll N=2e5+10,M=1e7+10;
ll n,m,a[N],st[N],rt[N],cnt,n_lsh;
struct node{ll ls,rs,l,r,val;}tr[M];

il ll read()
{
    rg char ch=gc;rg ll x=0;rg bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void build(ll x,ll l,ll r)
{
    ++cnt;tr[x].l=l,tr[x].r=r;if(l==r)return;
    tr[x].ls=cnt+1;build(tr[x].ls,l,(l+r)>>1);tr[x].rs=cnt+1;build(tr[x].rs,((l+r)>>1)+1,r);return;
}
il void updat(ll x,ll dat)
{
    ++cnt;tr[cnt]=tr[x];++tr[cnt].val;if(tr[cnt].l==tr[cnt].r)return;
    ll mid=(tr[cnt].l+tr[cnt].r)>>1;
    if(dat<=mid){tr[cnt].ls=cnt+1;updat(tr[x].ls,dat);}else{tr[cnt].rs=cnt+1;updat(tr[x].rs,dat);}
}
il ll query(ll x1,ll x2,ll dat)
{
    if(tr[x1].l==tr[x1].r)return tr[x1].l;ll ret=tr[tr[x2].ls].val-tr[tr[x1].ls].val;
    if(retreturn query(tr[x1].rs,tr[x2].rs,dat-ret);return query(tr[x1].ls,tr[x2].ls,dat);
}

int main()
{
//     freopen("zxs.in","r",stdin);freopen("zxs.out","w",stdout);
    n=read(),m=read();rp(i,1,n)a[i]=st[i]=read();sort(st+1,st+1+n);n_lsh=unique(st+1,st+1+n)-st-1;rp(i,1,n)a[i]=lower_bound(st+1,st+n_lsh+1,a[i])-st;
    rt[0]=1;build(1,1,n_lsh);
    rp(i,1,n){rt[i]=cnt+1;updat(rt[i-1],a[i]);}rp(i,1,m){ll l=read(),r=read(),x=read();printf("%lld\n",st[query(rt[l-1],rt[r],x)]);}
    return 0;
}
View Code

可持久化数组

不得不吐槽下这个名字好傻逼嗷,,,

然后先放个例题

其实就直接主席树就成.

要$cue$一下这个知识点主要是为了给后面可持久化并查集打个铺垫$QwQ$

昂然后有点儿浪费空间其实,,,因为没有任何区间信息要记的其实,,,

然后我就考虑了下能不能把中间那些空节点都删了,就说从一棵二叉树变成一棵普通的深度为1的树

然后就发现我是傻逼这样的空间复杂度显然是错的这不是暴力的思路嘛喂,,,

所以还是老老实实写主席树趴$QwQ$

对了,关于这题例题的话还要说下,就如果是$30pts$后面全$WA$,记得好好读题$QwQ$

#include
using namespace std;
#define il inline
#define gc getchar()
#define mp make_pair
#define ri register int
#define rc register char
#define rb register bool
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define lb(x) lower_bound(b+1,b+1+num,x)-b
#define ub(x) upper_bound(b+1,b+1+num,x)-b

const int N=1e6+10;
int n,m,nod_cnt,rt[N];
struct node{int ls,rs,val;}tr[N*100];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
int build(ri l,ri r)
{
    ri nw=++nod_cnt;if(l==r)return tr[nw].val=read(),nw;
    ri mid=(l+r)>>1;tr[nw].ls=build(l,mid);tr[nw].rs=build(mid+1,r);return nw;
}
int insert(ri x,ri l,ri r,ri to,ri dat)
{
    ri nw=++nod_cnt;tr[nw]=tr[x];if(l==r)return tr[nw].val=dat,nw;
    ri mid=(l+r)>>1;to<=mid?tr[nw].ls=insert(tr[x].ls,l,mid,to,dat):tr[nw].rs=insert(tr[x].rs,mid+1,r,to,dat);
    return nw;
}
int query(ri nw,ri l,ri r,ri to)
{
    if(l==r)return tr[nw].val;
    ri mid=(l+r)>>1;return to<=mid?query(tr[nw].ls,l,mid,to):query(tr[nw].rs,mid+1,r,to);
}
void print(ri nw,ri l,ri r)
{
    if(l==r){printf("%d ",tr[nw].val);return;}
    ri mid=(l+r)>>1;print(tr[nw].ls,l,mid);print(tr[nw].rs,mid+1,r);
}

int main()
{
    freopen("3919.in","r",stdin);freopen("3919.out","w",stdout);
    n=read();m=read();rt[0]=build(1,n);
    rp(i,1,m)
    {
        ri pre=read(),opt=read();
        if(opt==1){ri pos=read(),dat=read();rt[i]=insert(rt[pre],1,n,pos,dat);}
        else{ri pos=read();printf("%d\n",query(rt[pre],1,n,pos));rt[i]=rt[pre];}
    }
    //rp(i,0,m)print(rt[i],1,n),printf("\n");
    return 0;
}
View Code

可持久化并查集

同样先放个例题$QwQ$

考虑维护一个数组$fa$,发现每次合并的时候只会修改一个点的值,然后又要可持久化,自然而然想到可持久化数组,,,?

然后就做完了,记得按秩合并鸭$QwQ$

 

#include
using namespace std;
#define il inline
#define gc getchar()
#define mp make_pair
#define ri register int
#define rc register char
#define rb register bool
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define lb(x) lower_bound(b+1,b+1+num,x)-b
#define ub(x) upper_bound(b+1,b+1+num,x)-b

const int N=1e6+10;
int n,m,nod_cnt,rt[N];
struct node{int ls,rs,val,sz;}tr[N*100];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
int build(ri l,ri r)
{
    ri nw=++nod_cnt;if(l==r)return tr[nw].val=l,tr[nw].sz=1,nw;
    ri mid=(l+r)>>1;tr[nw].ls=build(l,mid);tr[nw].rs=build(mid+1,r);return nw;
}
int insert(ri x,ri l,ri r,ri to,ri dat)
{
    ri nw=++nod_cnt;tr[nw]=tr[x];if(l==r)return tr[nw].val=dat,nw;
    ri mid=(l+r)>>1;to<=mid?tr[nw].ls=insert(tr[x].ls,l,mid,to,dat):tr[nw].rs=insert(tr[x].rs,mid+1,r,to,dat);
    return nw;
}
void modify(ri nw,ri l,ri r,ri to,ri dat)
{
    if(l==r)return void(tr[nw].sz=dat);
    ri mid=(l+r)>>1;to<=mid?modify(tr[nw].ls,l,mid,to,dat):modify(tr[nw].rs,mid+1,r,to,dat);
}
int queryfa(ri nw,ri l,ri r,ri to)
{
    if(l==r)return tr[nw].val;
    ri mid=(l+r)>>1;return to<=mid?queryfa(tr[nw].ls,l,mid,to):queryfa(tr[nw].rs,mid+1,r,to);
}
int querysz(ri nw,ri l,ri r,ri to)
{
    if(l==r)return tr[nw].sz;
    ri mid=(l+r)>>1;return to<=mid?querysz(tr[nw].ls,l,mid,to):querysz(tr[nw].rs,mid+1,r,to);
}
int fd(ri tim,ri nw){ri fa=queryfa(rt[tim],1,n,nw);return fa==nw?fa:fd(tim,fa);}

int main()
{
    freopen("3402.in","r",stdin);freopen("3402.out","w",stdout);
    n=read();m=read();rt[0]=build(1,n);
    //rp(i,1,n)printf("fa[%d]=%d,sz[%d]=%d\n",i,queryfa(rt[0],1,n,i),i,querysz(rt[0],1,n,i));
    rp(i,1,m)
    {
        ri opt=read();
        switch(opt)
        {
        case 1:
        {
            ri fx=fd(i-1,read()),fy=fd(i-1,read());if(fx==fy){rt[i]=rt[i-1];continue;}
            ri szx=querysz(rt[i-1],1,n,fx),szy=querysz(rt[i-1],1,n,fy);
            if(szx<szy)swap(fx,fy),swap(szx,szy);
            rt[i]=insert(rt[i-1],1,n,fy,fx);modify(rt[i],1,n,fx,szx+szy);
            break;
        }
        case 2:{rt[i]=rt[read()];break;}
        case 3:{rt[i]=rt[i-1];ri fx=fd(i,read()),fy=fd(i,read());printf("%d\n",fx==fy);break;}
        }
        //printf("tim=%d:\n",i);
        //rp(j,1,n)printf("  fa[%d]=%d,sz[%d]=%d\n",j,queryfa(rt[i],1,n,j),j,querysz(rt[i],1,n,j));
    }
    return 0;
}
View Code

 

可持久化平衡树

先放例题鸭$QwQ$

然后咕咕,我学完$treap$再来港这题$QwQ$

你可能感兴趣的:(可持久化学习笔记合集)