知识点:主席树

概念

主席树,又称可持久化线段树,
其实就是对于每一次修改之后的树的状态的储存
也就是说我们可以对这个树的任意一个状态进行操作

实现

我们考虑修改之后到底修改了多少个点,
也就是修改之后的线段树和修改之前的线段树有哪些点是不同的
通过储存这些修改的点
空间复杂度就可以达到\(O(n+n*log_n)\)
但是时间复杂度依旧是\(O(log_n)\)

打个比方

A因作业没做完要抄B的作业
但A因为时间不够,A想尽可能的少抄
怎么实现呢,如果A发现B的作业的某一道题错了
A就在自己的作业的那一道题上打个标记
其它的题就直接链接到B的作业上去了
但是如果B要改作业的答案呢?
很明显,A会把B摁住不让他修改
因为B修改之后,A的作业就需要重新抄写
也就是说,
老师的查作业方法一定是问A某道题的答案是什么
而并不能看A的作业答案
这里也反映出主席树的一个限制,
一个状态定下来之后就不能修改了

例题

题目

代码

#include<iostream>
using namespace std;
struct node
{
    int l,r;
    int lson;
    int rson;
    int maxx;
}tre[32*100000];
int n,q;
int cm;
int cnt;
int k,l,r;
int p,v;
int tot;
int root[1000005];
int build(int l,int r)
{
    int now;
    tot++;
    now=tot;
    tre[tot].l=l;
    tre[tot].r=r;
    if(l==r)
    {
        cin>>tre[tot].maxx;
        return tot;
    }
    int mid=(l+r)>>1;
    tre[now].lson=build(l,mid);
    tre[now].rson=build(mid+1,r);
    tre[now].maxx=max(tre[tre[now].lson].maxx,tre[tre[now].rson].maxx);
    return now;
}
int ask(int k,int l,int r)
{
    if(tre[k].r<l||r<tre[k].l)
        return 0;
    if(l<=tre[k].l&&tre[k].r<=r)
        return tre[k].maxx;
    return max(ask(tre[k].lson,l,r),ask(tre[k].rson,l,r));
}
int change(int k,int p,int v)
{
    int now;
    int mid=(tre[k].l+tre[k].r)>>1;
    if(tre[k].l==tre[k].r&&tre[k].l==p)
    {
        tre[++tot].l=tre[k].l;
        tre[tot].r=tre[k].r;
        tre[tot].maxx=v;
        return tot;
    }
    if(tre[k].l<=p&&p<=mid)
    {
        tot++;
        now=tot;
        tre[tot].l=tre[k].l;
        tre[tot].r=tre[k].r;
        tre[tot].rson=tre[k].rson;
        tre[tot].lson=change(tre[k].lson,p,v);
    }
    else
    {
        tot++;
        now=tot;
        tre[tot].l=tre[k].l;
        tre[tot].r=tre[k].r;
        tre[tot].lson=tre[k].lson;
        tre[tot].rson=change(tre[k].rson,p,v);
    }
    tre[now].maxx=max(tre[tre[now].lson].maxx,tre[tre[now].rson].maxx);
    return now;
}
int main()
{
//  ios::sync_with_stdio(false);
    cin>>n>>q;
    root[++cnt]=1;
    build(1,n);
    for(int i=1;i<=q;i++)
    {
        cin>>cm;
        if(cm==0)
        {
            cin>>k>>l>>r;
            cout<<ask(root[k],l,r)<<'\n';
        }
        else
        {
            cin>>k>>p>>v;
            root[++cnt]=change(root[k],p,v);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/11742087.html