K-th Number 主席树基础题
Source
My Solution
题意:给出一个数组,每次询问这个数组的区间[L, R]内第k大的数是什么。
主席树基础题
主席树,又称可持久化线段树,是对于数组的每个前缀a[1...i]建立一颗线段树,并且a[1...i]的线段树和a[1...i+1]的线段树的区别是只有树上的一条链不同,所以每次对于一颗新的线段树其实只是添加一条长度为logn的链。
它的核心是寻找公共节点和主席树的加减性。
时间复杂度每次查询和修改都是logn,并且空间复杂度大概是O(nlogn)所以一般开20*MAXN的数组应该没有问题。
这里推荐一篇讲解主席树讲得很好的博客
树状结构之主席树
树状结构之主席树
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 8;
//Chairman_Tree
int tot, sz;
int a[MAXN], b[MAXN], root[20*MAXN], ls[20*MAXN], rs[20*MAXN], sum[20*MAXN];
inline void _build(int &o, int l, int r){
o = ++ tot;
sum[o] = 0;
if(l == r) return;
int mid = (l + r) >> 1;
_build(ls[o], l, mid);
_build(rs[o], mid + 1, r);
}
inline void update(int &o, int l, int r, int last, int p){
o = ++ tot;
ls[o] = ls[last];
rs[o] = rs[last];
sum[o] = sum[last] + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(ls[o], l, mid, ls[last], p); else update(rs[o], mid + 1, r, rs[last], p); } inline int _query(int ss, int tt, int l, int r, int k){ if(l == r) return l; int mid = (l + r) >> 1;
int cnt = sum[ls[tt]] - sum[ls[ss]];
if(k <= cnt) return _query(ls[ss], ls[tt], l, mid, k); else return _query(rs[ss], rs[tt], mid + 1, r, k - cnt); } int main() { #ifdef LOCAL freopen("a.txt", "r", stdin); //freopen("a.out", "w", stdout); int T = 1; while(T--){ #endif // LOCAL ios::sync_with_stdio(false); cin.tie(0); int n, m, i, ql, qr, x, ind; cin >> n >> m;
for(i = 1; i <= n; i++){ cin >> a[i];
b[i] = a[i];
}
sort(b + 1, b + n + 1);
sz = unique(b + 1, b + n + 1) - (b + 1);
for(i = 1; i <= n; i++){
a[i] = lower_bound(b + 1, b + sz + 1, a[i]) - b; //It is based on 1~n..
}
tot = 0;
_build(root[0], 1, sz);
for(i = 1; i <= n; i++){ update(root[i], 1, sz, root[i-1], a[i]); } while(m--){ cin >> ql >> qr >> x;
ind = _query(root[ql - 1], root[qr], 1, sz, x);
cout << b[ind] << "n";
}
#ifdef LOCAL
cout << endl;
}
#endif // LOCAL
return 0;
}
- THE END -
最后修改:2024年11月15日
非特殊说明,本博所有文章均为博主原创,未经许可不得转载。
如经许可后转载,请注明出处:https://prolightsfxjh.com/article/poj-2104-k-th-number/
共有 0 条评论