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