zoukankan      html  css  js  c++  java
  • 洛谷P3834 【模板】可持久化线段树 2/POJ2104 Kth Number 题解 主席树

    题目链接:https://www.luogu.com.cn/problem/P3834

    本题同 POJ2104 K-th Number http://poj.org/problem?id=2104

    题目大意:\(n\) 个数,\(m\) 次询问。每次询问要求求出区间 \([l,r]\) 范围内第 \(k\) 小的数。

    暴力解法

    每次取一个区间的副本并排序,然后求区间第 \(k\) 小的那个数。时间复杂度 \(O(n \cdot m \cdot \log n)\)。(50分)

    示例程序:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200020;
    
    int n, m, a[maxn], l, r, k, b[maxn];
    
    int main() {
        ios::sync_with_stdio(0);
        cin >> n >> m;
        for (int i = 1; i <= n; i ++)
            cin >> a[i];
        while (m --) {
            cin >> l >> r >> k;
            memcpy(b+l, a+l, sizeof(int)*(r-l+1));
            sort(b+l, b+r+1);
            cout << b[l+k-1] << endl;
        }
        return 0;
    }
    

    主席树

    对于原序列的每一个前缀 \([1 \ldots i]\) 建立出一棵线段树维护值域上每个数出现的次数,则这棵树是可减的。

    维护一棵权值线段树,每个节点 \(rt\) 保存数值为 \([ lson[rt], rson[rt] ]\) 的数的个数。

    对于每次询问的 \([L,R]\) 范围内第 \(k\) 小的数,

    \(t_1\) 为第 \(L-1\) 个版本的线段树,\(t_2\) 为第 \(R\) 个版本的线段树,则查询第 \(k\) 小的数,若 \(t_2\) 的左子树元素个数 \(\ge t_1 + k\) 的左子树元素个数 \(+ k\),则在左子树;否则,在右子树。

    示例代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200020;
    vector<int> v;
    inline int getid(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; }
    struct Node {
        int l, r, sum;
    } tree[maxn*40];
    int cnt, root[maxn];
    
    int n, m, a[maxn];
    
    void add(int l, int r, int pre, int &now, int p) {
        tree[now = ++cnt] = tree[pre];
        tree[now].sum ++;
        if (l == r) return;
        int mid = (l + r) / 2;
        if (p <= mid) add(l, mid, tree[pre].l, tree[now].l, p);
        else add(mid+1, r, tree[pre].r, tree[now].r, p);
    }
    
    int query(int l, int r, int rt1, int rt2, int k) {
        if (l == r) return l;
        int mid = (l + r) / 2;
        int tmp = tree[ tree[rt2].l ].sum - tree[ tree[rt1].l ].sum;
        if (k <= tmp) return query(l, mid, tree[rt1].l, tree[rt2].l, k);
        else return query(mid+1, r, tree[rt1].r, tree[rt2].r, k-tmp);
    }
    
    int main() {
        ios::sync_with_stdio(0);
        cin >> n >> m;
        for (int i = 1; i <= n; i ++) {
            cin >> 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 ++) {
            add(1, n, root[i-1], root[i], getid(a[i]));
        }
        while (m --) {
            int l, r, k;
            cin >> l >> r >> k;
            cout << v[query(1, n, root[l-1], root[r], k)-1] << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    网页图片垂直剧中 等比例缩放 黑白显示
    vs.net打包(自动检测环境并安装.net framwork)
    22个所见即所得在线Web编辑器
    js验证表单大全3
    js验证表单大全2
    开源界的5大开源许可协议
    ffmpeg参数使用说明2
    ffmpeg参数使用说明1
    js验证表单大全1
    【从零开始学Spring笔记】注解和XML整合开发
  • 原文地址:https://www.cnblogs.com/quanjun/p/15465259.html
Copyright © 2011-2022 走看看