zoukankan      html  css  js  c++  java
  • luogu3834 【模板】可持久化线段树1(主席树)

    关键字:线段树 可持久化

    线段树:当版本(即对应的原序列的区间[1,r])一定时,每个节点的left,right下标为值域,值为其对应的原序列区间[1,r]中元素大小在值域中的元素个数。

    可持久化:新版本(对应原序列[1,r])在旧版本(对应原序列[1,r-1])上建立,从树根向树叶构造,在旧版本的节点的旁边构造新版本的节点,值为旧版本节点值+1。搜索新版本树时,从新版本树根开始搜索即可。求区间第k大,同时遍历【1,l-1】对应版本树和【1,r】对应版本树,通过节点值的差来得到第k个节点。

    #include <cstdio>
    #include <cstring>
    #include <cassert>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    #define LOOP(i,n) for(int i=1; i<=n; i++)
    #define INF 0x3f3f3f3f
    const int MAX_ROOT=2e5;
    int Seq[MAX_ROOT];
    
    struct Node 
    {
        int Cnt;
        Node *LeftSon, *RightSon;
        Node() 
        {
            Cnt = 0;
            LeftSon = RightSon = NULL;
        }
    };
    
    Node *_roots[MAX_ROOT];
    int _vCount;
    int MinL, MaxR;
    
    void Init(int l, int r) 
    {
        _vCount = 0;
        MinL = l;
        MaxR = r;
        _roots[0] = new Node();
    }
    
    Node *Update(Node *prev, Node *&cur, int l, int r, int p) 
    {
        cur = new Node();
        *cur = *prev;
        cur->Cnt++;
        if (l == r)
            return cur;
        int mid = (r - l) / 2 + l;
        if (p <= mid) 
        {
            if (!prev->LeftSon)
                prev->LeftSon = new Node();
            Update(prev->LeftSon, cur->LeftSon, l, mid, p);
        }
        else 
        {
            if (!prev->RightSon)
                prev->RightSon = new Node();
            Update(prev->RightSon, cur->RightSon, mid + 1, r, p);
        }
        return cur;
    }
    
    int Query(Node *prev, Node *cur, int l, int r, int k) 
    {
        if (l == r)
            return l;
        int prevLeft = prev->LeftSon ? prev->LeftSon->Cnt : 0, curLeft = cur->LeftSon ? cur->LeftSon->Cnt : 0;
        int leftCnt = curLeft - prevLeft;
        int mid = (r - l) / 2 + l;
        if (k <= leftCnt) 
        {
            if (!prev->LeftSon)
                prev->LeftSon = new Node();
            return Query(prev->LeftSon, cur->LeftSon, l, mid, k);
        }
        else 
        {
            if (!prev->RightSon)
                prev->RightSon = new Node();
            return Query(prev->RightSon, cur->RightSon, mid + 1, r, k - leftCnt);
        }
    }
    
    void Update(int r) 
    {
        Update(_roots[r - 1], _roots[r], MinL, MaxR, Seq[r]);
    }
    
    int Query(int l, int r, int k) 
    {
        return Query(_roots[l - 1], _roots[r], MinL, MaxR, k);
    }
    
    int main() 
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        int seqCnt, queryCnt, l, r, k, minL = INF, maxR = -INF;
        scanf("%d%d", &seqCnt, &queryCnt);
        LOOP(i, seqCnt) 
        {
            scanf("%d", i + Seq);
            minL = min(Seq[i], minL);
            maxR = max(Seq[i], maxR);
        }
        Init(minL, maxR);
        LOOP(i, seqCnt)
            Update(i);
        LOOP(i, queryCnt) 
        {
            scanf("%d%d%d", &l, &r, &k);
            printf("%d
    ", Query(l, r, k));
        }
        return 0;
    }
  • 相关阅读:
    Linux上的文件管理类命令都有哪些,其常用的使用方法及其相关示例演示
    总结软连接和硬连接区别,并用实例操作说明
    描述文件的元数据信息有哪些,分别表示什么含义,如何查看?如何修改文件的时间戳信息?
    Git Shell push_code 脚本
    YDD的铁皮锅——C/C++内存概念
    Linux Shell 常见用法及问题
    MFC 设置鼠标样式(SetSystemCursor函数问题)
    Qt QTableView自定义列表(插入图片)
    Github libinjection库研究总结
    Windows/Linux:VMware虚拟机用内网IP通讯
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8438289.html
Copyright © 2011-2022 走看看