[hdu2665 Kth number]区间第k大数

来源:互联网 发布:淘宝超市加盟 编辑:程序博客网 时间:2024/05/29 03:28

题意:给n个数,m次询问(l, r, k),每次询问区间[l, r]内的第k大数是多少
想法:区间问题。
* 暴力做法,将数据提取出来,然后套O(n)的划分,总复杂度O(mn)
* 在线段树上保存信息。比如归并树,保存归并排序的整个过程并对应到每个节点区间。或者像划分树那样,保存划分的结果,并维护一下进入到子区间的数的个数,这个信息可以在查询的时候用来确定第k大数被划到了左边还是右边。使用归并树复杂度为O(nlogn+mlog3n),划分树复杂度为O(nlogn+mlogn)
* 可持久化线段树,也被称之为主席树。对每个前缀区间建一棵线段树保存数字区间的出现次数和,那么任一个区间的信息就可以由两颗线段树相减得到,然后就是在线段树上二分了。。复杂度依然是O(nlogn+mlogn)。另外可持久化体现在节点的共用上,这里的实现比较巧妙,也是保证空间复杂度的关键。
* 如果这个题可以离线做,也可以考虑考虑莫队算法。需要用到一个支持插入、删除、求rank的数据结构,用平衡树的话复杂度为O(nmlogn)

划分树:

#include <bits/stdc++.h>using namespace std;#ifndef ONLINE_JUDGE#include "local.h"#endif // ONLINE_JUDGE#define pb(x)                   push_back(x)#define mp(x, y)                make_pair(x, y)#define all(a)                  (a).begin(), (a).end()#define mset(a, x)              memset(a, x, sizeof(a))#define mcpy(a, b)              memcpy(a, b, sizeof(b))#define up(a, b)                for (int a = 0; a < (b); a ++)#define down(a, b)              for (int a = b - 1; (a) >= 0; a --)#define rep(i, a, b)            for (int i = a; i <= (b); i ++)#define rrep(i, a, b)           for (int i = a; i >= (b); i --)#define cas()                   int T, cas = 0; cin >> T; while (T --)#define printCas(ch)            printf("Case #%d:%c", ++ cas, ch)#define watch(ele)              cout << ele << endl;#define in(a)                   scanf("%d", &a)typedef long long ll;typedef pair<int, int> pii;template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}const int N = 1e5 + 7;struct SegTree {    int sum[20][N], seq[20][N];    void init(int a[]) {        memcpy(seq[0], a, sizeof(seq[0]));    }    void build(int b[], int d, int l, int r) {        if (l == r) return;        int m = l + r >> 1, mid = b[m], cnt = l;        rep(i, l, r) if (seq[d][i] < mid) cnt ++;        int tl = l, tr = m + 1;        rep(i, l, r) {            int val = seq[d][i];            sum[d][i] = sum[d][i - 1];            if (val < mid) seq[d + 1][tl ++] = val, sum[d][i] ++;            if (val > mid) seq[d + 1][tr ++] = val;            if (val == mid) {                if (cnt <= m) seq[d + 1][tl ++] = val, sum[d][i] ++, cnt ++;                else seq[d + 1][tr ++] = val;            }        }        build(b, d + 1, l, m);        build(b, d + 1, m + 1, r);    }    int query(int L, int R, int k, int d, int l, int r) {        if (l == r) return seq[d][l];        int m = l + r >> 1, cr = sum[d][R] - sum[d][l - 1], cl = sum[d][L - 1] - sum[d][l - 1], buf = cr - cl;        if (buf >= k) return query(l + cl, l + cr - 1, k, d + 1, l, m);        else return query(m + 1 + L - l - cl, m + R - l + 1 - cr, k - buf, d + 1, m + 1, r);    }};SegTree st;int n, m, s, t, k, a[N], b[N];int main() {#ifndef ONLINE_JUDGE    freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);#endif // ONLINE_JUDGE    cas() {        cin >> n >> m;        up(i, n) in(a[i + 1]);        mcpy(b, a);        sort(b + 1, b + 1 + n);        st.init(a);        st.build(b, 0, 1, n);        while (m --) {            in(s); in(t); in(k);            printf("%d\n", st.query(s, t, k, 0, 1, n));        }    }    return 0;}

主席树:

#include <bits/stdc++.h>using namespace std;#ifndef ONLINE_JUDGE#include "local.h"#endif // ONLINE_JUDGE#define pb(x)                   push_back(x)#define mp(x, y)                make_pair(x, y)#define all(a)                  (a).begin(), (a).end()#define mset(a, x)              memset(a, x, sizeof(a))#define mcpy(a, b)              memcpy(a, b, sizeof(b))#define up(a, b)                for (int a = 0; a < (b); a ++)#define down(a, b)              for (int a = b - 1; (a) >= 0; a --)#define rep(i, a, b)            for (int i = a; i <= (b); i ++)#define rrep(i, a, b)           for (int i = a; i >= (b); i --)#define cas()                   int T, cas = 0; cin >> T; while (T --)#define printCas(ch)            printf("Case #%d:%c", ++ cas, ch)#define watch(ele)              cout << ele << endl;#define in(a)                   scanf("%d", &a)typedef long long ll;typedef pair<int, int> pii;template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}const int N = 1e5 + 7;struct SegTree {    struct Node {        int lp, rp, sum;    };    int c;    Node node[N * 22];    void clear() {        c = 0;        mset(node, 0);    }    void build(int l, int r, int &rt) {        rt = c ++;        if (l == r) return;        int m = l + r >> 1;        build(l, m, node[rt].lp);        build(m + 1, r, node[rt].rp);    }    void update(int x, int v, int last, int l, int r, int &rt) {        rt = c ++;        node[rt] = node[last];        node[rt].sum += v;        if (l == r) return;        int m = l + r >> 1;        if (x <= m) update(x, v, node[last].lp, l, m, node[rt].lp);        else update(x, v, node[last].rp, m + 1, r, node[rt].rp);    }    int query(int s, int t, int k, int l, int r) {        if (l == r) return l;        int m = l + r >> 1, buf = node[node[t].lp].sum - node[node[s].lp].sum;        if (buf >= k) return query(node[s].lp, node[t].lp, k, l, m);        else return query(node[s].rp, node[t].rp, k - buf, m + 1, r);    }};SegTree st;int n, m, s, t, k, sz, a[N], b[N], root[N];int main() {#ifndef ONLINE_JUDGE    freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);#endif // ONLINE_JUDGE    cas() {        cin >> n >> m;        up(i, n) in(a[i]);        up(i, n) b[i] = a[i];        sort(b, b + n);        sz = unique(b, b + n) - b;        up(i, n) a[i] = lower_bound(b, b + sz, a[i]) - b;        st.clear();        st.build(0, sz - 1, root[0]);        up(i, n) st.update(a[i], 1, root[i], 0, sz - 1, root[i + 1]);        while (m --) {            in(s); in(t); in(k);            printf("%d\n", b[st.query(root[s - 1], root[t], k, 0, sz - 1)]);        }    }    return 0;}
0 0