可持久化数据结构(待补)

1.trie的可持久化

2.线段树的可持久化(主席树)

可持久化的前提:本身的拓扑结构不变

可持久化解决的问题:类似于girhub 管理所有的历史版本和现在的版本并支持回滚

就是可以存下来数据结构的所有历史版本

git的操作是只会记录每一个版本相比于前一个版本的区别在哪 这里也是用这种思想


1.可持久化trie

普通的trie到版本一

版本一到版本二

 版本二到版本三

 版本三到版本四

 这题就是可持久化的trie树的操作 这里画的边上的字母应该在点上的 这样才好理解

1.最大异或和

256. 最大异或和 - AcWing题库

 

#include <bits/stdc++.h>
using namespace std;
const int N=600010,M=N*25;
int n,m;
int s[N];
int tr[M][2],max_id[M];
int root[M],idx;
void Insert(int i,int k,int p,int q)
{
    if(k<0)
    {
        max_id[q]=i;
        return ;
    }
    int v=s[i]>>k&1;
    if(p) tr[q][v^1]=tr[p][v^1];
    tr[q][v]=++idx;
    Insert(i,k-1,tr[p][v],tr[q][v]);
    max_id[q]=max(max_id[tr[q][0]],max_id[tr[q][1]]);
}
int query(int root,int c,int l)
{
    int p=root;
    for(int i=23;i>=0;i--)
    {
        int v=c>>i&1;
        if(max_id[tr[p][v^1]]>=l)
        {
            p=tr[p][v^1];
        }
        else p=tr[p][v];
    }
    return c^s[max_id[p]];
}
int main()
{
    scanf("%d%d",&n,&m);
    max_id[0]=-1;
    root[0]=++idx;
    Insert(0,23,0,root[0]);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        s[i]=s[i-1]^x;
        root[i]=++idx;
        Insert(i,23,root[i-1],root[i]);
    }
    char op[2];
    int l,r,x;
    while(m--)
    {
        scanf("%s",op);
        if(*op=='A')
        {
            scanf("%d",&x);
            n++;
            s[n]=s[n-1]^x;
            root[n]=++idx;
            Insert(n,23,root[n-1],root[n]);
        }
        else
        {
            scanf("%d%d%d",&l,&r,&x);
            printf("%d\n",query(root[r-1],s[n]^x,l-1));
        }
    }
    return 0;
}

2.可持久化线段树   主席树

一共有m次修改 会有m+1个版本

由于有多个版本 所以树的建立肯定不是满足堆的存储的 而是用指针的方式来存

struct node
{
    int l,r;//左右儿子
    int cnt; //当前区间中一共有多少个数
}

可持久线段树很难处理区间修改操作

2.第k小数

255. 第K小数 - AcWing题库

#include <bits/stdc++.h>
using namespace std;
const int N=100010,M=10010;
int n,m;
int a[N];
vector<int> nums;
struct Node
{
    int l,r;
    int cnt;
}tr[4*N+N*17];
int root[N],idx;
int find(int x)
{
    return lower_bound(nums.begin(),nums.end(),x)-nums.begin();
}
int build(int l,int r)
{
    int p=++idx;
    if(l==r) return p;
    int mid=l+r>>1;
    tr[p].l=build(l,mid),tr[p].r=build(mid+1,r);
    return p;
}
int insert(int p,int l,int r,int x)
{
    int q=++idx;
    tr[q]=tr[p];
    if(l==r)
    {
        tr[q].cnt++;
        return q;
    }
    int mid=l+r>>1;
    if(x<=mid) tr[q].l=insert(tr[p].l,l,mid,x);
    else tr[q].r=insert(tr[p].r,mid+1,r,x);
    tr[q].cnt=tr[tr[q].l].cnt+tr[tr[q].r].cnt;
    return q;
}
int query(int q,int p,int l,int r,int k)
{
    if(l==r) return r;
    int cnt=tr[tr[q].l].cnt-tr[tr[p].l].cnt;
    int mid=l+r>>1;
    if(k<=cnt)
        return query(tr[q].l,tr[p].l,l,mid,k);
    else return query(tr[q].r,tr[p].r,mid+1,r,k-cnt);

}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        nums.push_back(a[i]);
    }
    sort(nums.begin(),nums.end());
    nums.erase(unique(nums.begin(),nums.end()),nums.end());
    root[0]=build(0,nums.size()-1);
    for(int i=1;i<=n;i++)
    {
        root[i]=insert(root[i-1],0,nums.size()-1,find(a[i]));
    }
    while(m--)
    {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",nums[query(root[r],root[l-1],0,nums.size()-1,k)]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值