标签:
题目链接:点击打开链接
思路:treap树模板题, 可以动态维护一个有序表, 支持在O(logN)的时间内完成插入、删除一个元素和查找第K大元素的任务。 当然, treap树能做到的还远远不止这些, 常常与其他数据结构嵌套。
treap树是一种平衡二叉搜索树, 既满足堆的条件, 又满足排序二叉树的条件。
细节参见代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <stack> #include <bitset> #include <cstdlib> #include <cmath> #include <set> #include <list> #include <deque> #include <map> #include <queue> #include <ctime> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const ld eps = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = 0x3f3f3f3f; const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 3e4 + 10; int T,n,m,a[maxn], cc, v; struct treap { int root, treapcnt, key[maxn],priority[maxn], childs[maxn][2], cnt[maxn], _size[maxn]; treap() { root = 0; treapcnt = 1; priority[0] = INF; _size[0] = 0; } void update(int x) { _size[x] = _size[childs[x][0]] + cnt[x] + _size[childs[x][1]]; } void _rotate(int &x, int t) { int y = childs[x][t]; //为了维持平衡而做的旋转操作,它并不直观 childs[x][t] = childs[y][1-t]; childs[y][1-t] = x; update(x); update(y); x = y; } void _insert(int &x, int k) { if(x) { //x == 0 表示该结点为空, 反之非空 if(key[x] == k) cnt[x]++; //cnt[x]表示结点x的值的个数,key[x]表示结点x的值 else { int t = key[x] < k; //根据排序二叉树规则递归下去 _insert(childs[x][t], k); if(priority[childs[x][t]] < priority[x]) { //根据堆排序规则 _rotate(x, t); } } } else { x = treapcnt++; //创建新的结点 key[x] = k; cnt[x] = 1; priority[x] = rand(); //如果优先级是随机的,那么可以证明treap的期望深度是logN childs[x][0] = childs[x][1] = 0; //0表示为空 } update(x); } void _erase(int &x, int k) { if(key[x] == k) { if(cnt[x] > 1) --cnt[x]; else { if(childs[x][0] == 0 && childs[x][1] == 0) { x = 0; return ; //x设为0表示空 } int t = priority[childs[x][0]] > priority[childs[x][1]]; _rotate(x, t); //直到把该结点旋转到叶子再删除 _erase(x, k); } } else _erase(childs[x][key[x]<k], k); update(x); } int _getKth(int &x, int k) { if(k <= _size[childs[x][0]]) return _getKth(childs[x][0], k); //size[x]表示以x为根的子树的值得个数 k -= _size[childs[x][0]] + cnt[x]; //如果在右边,那么将要找右边的第k-size小的数 if(k <= 0) return key[x]; return _getKth(childs[x][1], k); } void insert(int k) { _insert(root, k); } void erase(int k) { _erase(root, k); } int getKth(int k) { return _getKth(root, k); } }; int main() { while(~scanf("%d%d",&n,&m)) { treap g; for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } cc = 1; for(int i = 1; i <= m; i++) { scanf("%d",&v); while(v >= cc) g.insert(a[cc++]); printf("%d\n", g.getKth(i)); } } return 0; }
标签:
原文地址:http://blog.csdn.net/weizhuwyzc000/article/details/51397199