K-th Number POJ - 2104 (主席树 | 划分树)(附动态区间主席树模板)

K-th Number POJ - 2104

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1…n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: “What would be the k-th number in a[i…j] segment, if this segment was sorted?”
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2…5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The first line of the input file contains n — the size of the array, and m — the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 10 9 by their absolute values — the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
For each question output the answer to it — the k-th number in sorted a[i…j] segment.

Sample Input

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output

5
6
3
Hint
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.

Solution

 划分树,每次查询 O(logn)
也可用主席树解决。

AC Code(划分树)

#include <iostream>
#include <algorithm>

using namespace std;
const int maxn = 100010;
int tree[20][maxn];//表示每层每个位置的值
int sorted[maxn];//已经排序好的数
int toLeft[20][maxn];//toLeft[p][i]表示第i层从1到i有数分入左边

/**
 *
 * @param l Always 1
 * @param r Always n
 * @param dep Always 0
 */
void build(int l, int r, int dep) {
    if (l == r)return;
    int mid = (l + r) >> 1;
    int same = mid - l + 1;//表示等于中间值而且被分入左边的个数
    for (int i = l; i <= r; i++) //注意是l,不是one
        if (tree[dep][i] < sorted[mid])
            same--;
    int lpos = l;
    int rpos = mid + 1;
    for (int i = l; i <= r; i++) {
        if (tree[dep][i] < sorted[mid])
            tree[dep + 1][lpos++] = tree[dep][i];
        else if (tree[dep][i] == sorted[mid] && same > 0) {
            tree[dep + 1][lpos++] = tree[dep][i];
            same--;
        } else
            tree[dep + 1][rpos++] = tree[dep][i];
        toLeft[dep][i] = toLeft[dep][l - 1] + lpos - l;
    }
    build(l, mid, dep + 1);
    build(mid + 1, r, dep + 1);
}


/**
 *
 * @param L ALWAYS 1
 * @param R ALWAYS N
 * @param l 1-based, inclusive.
 * @param r 1-based, inclusive.
 * @param dep ALWAYS 0
 * @param k 1-based.
 * @return
 */
int query(int L, int R, int l, int r, int dep, int k) {
    if (l == r)return tree[dep][l];
    int mid = (L + R) >> 1;
    int cnt = toLeft[dep][r] - toLeft[dep][l - 1];
    if (cnt >= k) {
        int newL = L + toLeft[dep][l - 1] - toLeft[dep][L - 1];
        int newR = newL + cnt - 1;
        return query(L, mid, newL, newR, dep + 1, k);
    } else {
        int newr = r + toLeft[dep][R] - toLeft[dep][r];
        int newl = newr - (r - l - cnt);
        return query(mid + 1, R, newl, newr, dep + 1, k - cnt);
    }
}

int a[maxn];
int n, m;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> tree[0][i];
        sorted[i] = tree[0][i];
    }
    sort(sorted + 1, sorted + n + 1);
    build(1, n, 0);
    for (int i = 0; i < m; ++i) {
        int s, t, k;
        cin >> s >> t >> k;
        cout << query(1, n, s, t, 0, k) << "\n";
    }
}

AC Code (主席树)

#include <iostream>
#include <algorithm>
/*
 * 主席树,使用方法,将数组放入a数组,
 * 然后调用init方法。之后可直接query
 */
using namespace std;
const int MAXN = 100010;
const int M = MAXN * 30;
int n, q, m, tot;
int a[MAXN], t[MAXN];
int T[MAXN], lson[M], rson[M], c[M];

void initArray();

void Init_hash() {
    for (int i = 1; i <= n; i++)
        t[i] = a[i];
    sort(t + 1, t + 1 + n);
    m = static_cast<int>(unique(t + 1, t + 1 + n) - t - 1);
}

int build(int l, int r) {
    int root = tot++;
    c[root] = 0;
    if (l != r) {
        int mid = (l + r) >> 1;
        lson[root] = build(l, mid);
        rson[root] = build(mid + 1, r);
    }
    return root;
}

int _hash(int x) {
    return static_cast<int>(lower_bound(t + 1, t + 1 + m, x) - t);
}

int update(int root, int pos, int val) {
    int newroot = tot++, tmp = newroot;
    c[newroot] = c[root] + val;
    int l = 1, r = m;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            lson[newroot] = tot++;
            rson[newroot] = rson[root];
            newroot = lson[newroot];
            root = lson[root];
            r = mid;
        } else {
            rson[newroot] = tot++;
            lson[newroot] = lson[root];
            newroot = rson[newroot];
            root = rson[root];
            l = mid + 1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}

int queryHelp(int left_root, int right_root, int k) {
    int l = 1, r = m;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (c[lson[left_root]] - c[lson[right_root]] >= k) {
            r = mid;
            left_root = lson[left_root];
            right_root = lson[right_root];
        } else {
            l = mid + 1;
            k -= c[lson[left_root]] - c[lson[right_root]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}

void initArray() {
    Init_hash();
    T[n + 1] = build(1, m);
    for (int i = n; i; i--) {
        int pos = _hash(a[i]);
        T[i] = update(T[i + 1], pos, 1);
    }
}
/**
 *
 * @param l 1-based, inclusive.
 * @param r 1-based, inclusive.
 * @param k 1-based.
 * @return
 */
int query(int l, int r, int k) {
    return t[queryHelp(T[l], T[r + 1], k)];
}

int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> q;
    tot = 0;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    initArray();
    while (q--) {
        int l, r, k;
        cin >> l >> r >> k;
        cout << query(l, r, k) << "\n";
    }
    return 0;
}



动态区间主席树模板

#include <iostream>
#include <algorithm>
/*
 * 动态区间主席树
 *
 * 使用方法:
 *  数据存在a数组,1-based。
 *  t数组存所有a数组有的树和要修改的点的值
 *  区间离线输入完毕后调用init
 *  具体看main函数
 */
using namespace std;
const int MAXN = 60010;
const int M = 2500010;
int n, q, m, tot;
int a[MAXN], t[MAXN];
int T[MAXN], lson[M], rson[M], c[M];
int S[MAXN];
struct Query {
    int kind;
    int l, r, k;
} query[10010];

void init();

void Init_hash(int k) {
    sort(t, t + k);
    m = static_cast<int>(unique(t, t + k) - t);
}

int _hash(int x) {
    return static_cast<int>(lower_bound(t, t + m, x) - t);
}

int build(int l, int r) {
    int root = tot++;
    c[root] = 0;
    if (l != r) {
        int mid = (l + r) / 2;
        lson[root] = build(l, mid);
        rson[root] = build(mid + 1, r);
    }
    return root;
}

int Insert(int root, int pos, int val) {
    int newroot = tot++, tmp = newroot;
    int l = 0, r = m - 1;
    c[newroot] = c[root] + val;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            lson[newroot] = tot++;
            rson[newroot] = rson[root];
            newroot = lson[newroot];
            root = lson[root];
            r = mid;
        } else {
            rson[newroot] = tot++;
            lson[newroot] = lson[root];
            newroot = rson[newroot];
            root = rson[root];
            l = mid + 1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}

int lowbit(int x) {
    return x & (-x);
}

int use[MAXN];

void add(int x, int pos, int val) {
    while (x <= n) {
        S[x] = Insert(S[x], pos, val);
        x += lowbit(x);
    }
}

int sum(int x) {
    int ret = 0;
    while (x > 0) {
        ret += c[lson[use[x]]];
        x -= lowbit(x);
    }
    return ret;
}

int Query(int left, int right, int k) {
    int left_root = T[left - 1];
    int right_root = T[right];
    int l = 0, r = m - 1;
    for (int i = left - 1; i; i -= lowbit(i)) use[i] = S[i];
    for (int i = right; i; i -= lowbit(i)) use[i] = S[i];
    while (l < r) {
        int mid = (l + r) / 2;
        int tmp = sum(right) - sum(left - 1) + c[lson[right_root]] -
                  c[lson[left_root]];
        if (tmp >= k) {
            r = mid;
            for (int i = left - 1; i; i -= lowbit(i))
                use[i] = lson[use[i]];
            for (int i = right; i; i -= lowbit(i))
                use[i] = lson[use[i]];
            left_root = lson[left_root];
            right_root = lson[right_root];
        } else {
            l = mid + 1;
            k -= tmp;
            for (int i = left - 1; i; i -= lowbit(i))
                use[i] = rson[use[i]];
            for (int i = right; i; i -= lowbit(i))
                use[i] = rson[use[i]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}

void Modify(int x, int p, int d) {
    while (x <= n) {
        S[x] = Insert(S[x], p, d);
        x += lowbit(x);
    }
}

int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
    int Tcase;
    scanf("%d", &Tcase);
    while (Tcase--) {
        scanf("%d%d", &n, &q);
        tot = 0;
        m = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            t[m++] = a[i];
        }
        char op[10];
        for (int i = 0; i < q; i++) {
            scanf("%s", op);
            if (op[0] == 'Q') {
                query[i].kind = 0;
                scanf("%d%d%d", &query[i].l, &query[i].r, &query[i].k);
            } else {
                query[i].kind = 1;
                scanf("%d%d", &query[i].l, &query[i].r);
                t[m++] = query[i].r;
            }
        }
        init();
        for (int i = 0; i < q; i++) {
            if (query[i].kind == 0)
                printf("%d\n", t[Query(query[i].l, query[i].r, query[i].k)]);
            else {
                Modify(query[i].l, _hash(a[query[i].l]), -1);
                Modify(query[i].l, _hash(query[i].r), 1);
                a[query[i].l] = query[i].r;
            }
        }
    }
    return 0;
}

void init() {
    Init_hash(m);
    T[0] = build(0, m - 1);
    for (int i = 1; i <= n; i++)
            T[i] = Insert(T[i - 1], _hash(a[i]), 1);
    for (int i = 1; i <= n; i++)
            S[i] = T[0];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值