「模板」 主席树/可持久化线段树/函数式线段树

「模板」 主席树/可持久化线段树/函数式线段树


我的理解就是建一堆不同的根,然后指向相同的点,或说是一堆不同的树共用着一部分点。

挺费空间的,但是思路很巧妙啊,而且可持久化是很重要的东西。

代码更新于 2018.06.27。

#include <algorithm>
#include <cstdio>
#include <cstring>
const int MAXN=200010;
int n, m, q;
class PersistableSegmentTree
{
    private:
        int value[MAXN];
        struct Node
        {
            int v;
            Node *c[2];
            Node(int v):v(v)
            {
                c[0]=c[1]=nullptr;
            }
            Node(int l, int r)
            {
                c[0]=c[1]=nullptr;
                if(l==r)
                    return;
                int mid=l+r>>1;
                c[0]=new Node(l, mid);
                c[1]=new Node(mid+1, r);
            }
            ~Node(void)
            {
                if(c[0]!=nullptr)
                    delete c[0];
                if(c[1]!=nullptr)
                    delete c[1];
            }
        }*root[MAXN];
        void Update(Node* &i, Node* j, int l, int r, int v)
        {
            i=new Node(j->v+1);
            if(l==r)
            {
                i->v=j->v+1;
                return;
            }
            int mid=l+r>>1;
            memcpy(i->c, j->c, sizeof j->c);
            if(v>mid)
                Update(i->c[1], j->c[1], mid+1, r, v);
            else
                Update(i->c[0], j->c[0], l, mid, v);
        }
        int Find(Node* i, Node* j, int l, int r, int k)
        {
            if(l==r)
                return value[l];
            int mid=l+r>>1, v=j->c[0]->v-i->c[0]->v;
            if(k>v)
                return Find(i->c[1], j->c[1], mid+1, r, k-v);
            else
                return Find(i->c[0], j->c[0], l, mid, k);
        }
    public:
        PersistableSegmentTree(int n)
        {
            int *a=new int[n+1];
            std::fill(root, root+n+1, nullptr);
            for(int i=1; i<=n; ++i)
            {
                scanf("%d", &a[i]);
                value[i]=a[i];
            }
            std::sort(value+1, value+n+1);
            m=std::unique(value+1, value+n+1)-value-1;
            root[0]=new Node(1, m);
            for(int i=1, pos; i<=n; ++i)
            {
                pos=std::lower_bound(value+1, value+m+1, a[i])-value;
                Update(root[i], root[i-1], 1, m, pos);
            }
            delete []a;
        }
        void Find(int l, int r, int k)
        {
            printf("%d\n", Find(root[l-1], root[r], 1, m, k));
        }
}*T;
int main(int argc, char** argv)
{
    scanf("%d %d", &n, &q);
    T=new PersistableSegmentTree(n);
    for(int i=1, l, r, k; i<=n; ++i)
    {
        scanf("%d %d %d", &l, &r, &k);
        T->Find(l, r, k);
    }
    delete T;
    return 0;
}

谢谢阅读。

转载于:https://www.cnblogs.com/Capella/p/8575724.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值