洛谷P3919 【模板】可持久化数组 主席树

网址:https://www.luogu.org/problem/P3919

题意:

就是单点修改和单点查询历史版本(同时复制)。

题解:

先建一个线段树保存原版本,然后修改时就对需要修改的链建新版本,查询时就先复制树根(树根保留了树的儿子索引,所以复制了树根就相当于复制了这棵树),然后在新树中查询,结果是一样的(访问到的节点也是一样的)。所以这个是个主席树。代码不做解析,理解了洛谷P3848应该不难理解这个题。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000005
int num[MAXN];
int cnt=-1;
struct cheiftree
{
    struct node
    {
        int l,r,val;
    };
    node tr[MAXN*25];
    int rt[MAXN];
    void build(int l,int r,int &rt)//l一定是1,r一定是n
    {
        rt=++cnt;
        tr[rt].val=num[l];
        if(l==r)
            return;
        int m=(l+r)/2;
        build(l,m,tr[rt].l);
        build(m+1,r,tr[rt].r);
    }
    void update(int l,int r,int &rt,int lst,int x,int val)
    {
        rt=++cnt;
        tr[rt]=tr[lst];
        if(l==r)
        {
            tr[rt].val=val;
            return;
        }
        int m=(l+r)/2;
        if(x<=m)
            update(l,m,tr[rt].l,tr[lst].l,x,val);
        else
            update(m+1,r,tr[rt].r,tr[lst].r,x,val);
    }
    int query(int rt,int l,int r,int x)
    {
        if(l==r)
            return tr[rt].val;
        int m=(l+r)/2;
        if(x<=m)
            return query(tr[rt].l,l,m,x);
        else
            return query(tr[rt].r,m+1,r,x);
    }
};
cheiftree tr;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        cin>>num[i];
    tr.build(1,n,tr.rt[0]);
    int a,b,c,d;
    for(int i=1;i<=m;++i)
    {
        cin>>a>>b>>c;
        if(b==1)
        {
            cin>>d;
            tr.update(1,n,tr.rt[i],tr.rt[a],c,d);
        }
        else
        {
            tr.rt[i]=tr.rt[a];
            cout<<tr.query(tr.rt[i],1,n,c)<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Aya-Uchida/p/11249941.html