zoukankan      html  css  js  c++  java
  • 主席树模板(poj2104)

    主席树是可持久化线段树,可以记录线段树的历史版本。

    代码中和线段树不同的是,l,r记录的是左右子树编号,因为普通的线段树版本中,左右子树自然就是o<<1和o<<1|1,但是主席树中并不保证这个特性,所以需要记录一下。

    代码是

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    const int N = 1e5+7;
    int n, m, cnt, root[N], a[N], x, y, k;
    // 主席树解决区间第k大的问题
    // poj-2104
    struct node { int l, r, sum; } T[N*40]; // 左儿子右儿子编号 区间和 T[i]维护前缀1~i
    vector<int> v;
    int getid(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; }
    
    void update(int l, int r, int &x, int y, int pos) { // sum记录的是l和r之间的数
        T[++cnt] = T[y], T[cnt].sum++, x = cnt;
        if (l == r) return ;
        int mid = (l+r)>>1;
        if (mid >= pos) update(l, mid, T[x].l, T[y].l, pos);
        else update(mid+1, r, T[x].r, T[y].r, pos);
    }
    
    int query(int l, int r, int x, int y, int k) {
        if (l == r) return l;
        int mid = (l+r) / 2;
        int sum = T[T[y].l].sum - T[T[x].l].sum;
        if (sum >= k) return query(l, mid, T[x].l, T[y].l, k);
        return query(mid+1, r, T[x].r, T[y].r, k - sum);
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), v.push_back(a[i]);
        sort(v.begin(), v.end()), v.erase(unique(v.begin(), v.end()), v.end());
        for (int i = 1; i <= n; ++i) update(1, n, root[i], root[i-1], getid(a[i]));
        for (int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &x, &y, &k);
            printf("%d
    ", v[query(1,n,root[x-1],root[y],k)-1]);
        }
        return 0;
    }
  • 相关阅读:
    UML模型的基本概念
    Asp.net 2.0 发送电子邮件
    生活多了些颜色
    FLASH调用网页上的JS方法,以及FLASH全屏播放的方法
    HTC编程思想
    实用的SQL精妙语句
    自己写的封装好的简单的AJAXjavascript
    SQL Server对象名
    windows开关机日志
    RegisterWindowMessage
  • 原文地址:https://www.cnblogs.com/wenruo/p/5931297.html
Copyright © 2011-2022 走看看