您的位置:首页 > 其它

hdu 2852 KiKi's K-Number(BIT, 线段树,treap)

2014-12-08 23:48 357 查看
题意:

一个集合,初始为空。

三种操作,插入一个元素,删除一个元素,查询集合中大于a的第k个数。

解法一:

如果用 x[i] 记录 i 在集合中的个数,则可用BIT或segment tree解决。

解法二:

既然是名次问题,当然可以用treap解决。

这次又更新了我的treap模板 = =

原来的写法 在处理元素可重的情况 时,为每个重复的元素都建一个节点,因为右子树的元素大于等于根,所以在极端情况下会退化。

后来为每个节点加上count属性,表示该元素重复的个数,解决了这个问题~~~^_^

参考:

http://www.nocow.cn/index.php/Treap_C%2B%2B

下面是code

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <string>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
using namespace std;

#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))

const int inf  = 0x7fffffff;
const int Maxn = 100000;
typedef long long LL;

const double eps = 1e-10;

//#define DEBUG

int rankArr[Maxn+5];

typedef struct Node {
Node *ch[2];
int r;   // rank
int v;   // value
int s;   // size 名次树中子树结点个数
int cnt; // 有多少个相同的节点

int cmp(int x) const {
if (x == v) return -1;
return x < v ? 0 : 1;
}
void maintain() {
s = cnt;
if (ch[0] != NULL) s += ch[0]->s;
if (ch[1] != NULL) s += ch[1]->s;
}
}TreapNode;
class Treap {
public:
int find(TreapNode* o, int x) {
while (o != NULL) {
int d = o->cmp(x);
if (d == -1) return 1; // find
else o = o->ch[d];
}
return 0; // not find
}

// 返回小于等于x的数的个数
int rank(TreapNode* o, int x) {
int ret = 0;
while (o != NULL) {
int d = o->cmp(x);
if (d == 0) {
o = o->ch[0];
}
else {
if (o->ch[0] != NULL)
ret += o->ch[0]->s + o->cnt;
else
ret += o->cnt;
o = o->ch[1];
}
}
return ret; // not find
}

void insert(TreapNode* &o, int x) {
if (o == NULL) {
//o = new TreapNode();
//o->ch[0] = o->ch[1] = NULL;
//o->v = x;
//o->r = rand();
//o->s = 1;
make_node(o, x);
} else {
#ifdef DEBUG
cout << "d: " << "fa: " << o->v << " son: " << x << endl;
#endif // DEBUG

int d = o->cmp(x);
if (d == -1) {
o->cnt += 1;
#ifdef DEBUG
cout << "d: " << x << " add 1" << endl;
#endif // DEBUG
o->maintain();
return;
}
insert(o->ch[d], x);
if (o->ch[d]->r > o->r) {
#ifdef DEBUG
cout << "rotate: " << "fa: " << (o->v) << " son: " << (o->ch[d]->v) << " di: " << (d^1) << endl;
#endif // DEBUG
rotate(o, d^1);
}
}
o->maintain();
}
// 两棵子树:先把优先级较高的旋转到根
// 然后在另一棵子树中递归删除x
void remove(TreapNode* &o, int x) {
int d = o->cmp(x);
if (d == -1) {
if (o->cnt > 0)
o->cnt -= 1;
if (o->cnt == 0) {
TreapNode* u = o;
if (o->ch[0] == NULL) {
o = o->ch[1];
delete u;
} else if (o->ch[1] == NULL) {
o = o->ch[0];
delete u;
} else {
if (o->ch[0]->r > o->ch[1]->r) {
d = 1;
} else {
d = 0;
}
rotate(o, d);
remove(o->ch[d], x);
}
}
} else {
remove(o->ch[d], x);
}
if(o != NULL) o->maintain();
}
// 求第k大的值 0表示不存在
int kth(TreapNode* o, int k) {
if (o == NULL || k <= 0 || k > o->s) return 0;
int s = o->ch[1] == NULL ? 0 : o->ch[1]->s;
if (s+1 <= k && k <= s+o->cnt) return o->v;
else if (k <= s) return kth(o->ch[1], k);
else return kth(o->ch[0], k-s-o->cnt);
}
void mergeto(TreapNode* &src, TreapNode* &dst) {
if (src->ch[0] != NULL) mergeto(src->ch[0], dst);
if (src->ch[1] != NULL) mergeto(src->ch[1], dst);
insert(dst, src->v);
delete src;
src = NULL;
}
void make_node(TreapNode* &o, int x) {
o = new TreapNode();
o->ch[0] = o->ch[1] = NULL;
//o->r = rand();    // 直接调用 rand()
o->r = rankArr[x];  // 使用事先分配好的rank
o->s = 1;
o->v = x;
o->cnt = 1;
#ifdef DEBUG
cout << "new: " << " r: " << o->r << " v: " << o->v << " s: " << o->s << endl;
#endif // DEBUG
}
void destroy(TreapNode* &o) {
if (o == NULL) return;
if (o->ch[0] != NULL) destroy(o->ch[0]);
if (o->ch[1] != NULL) destroy(o->ch[1]);
delete o;
o = NULL;
}

private:
// 旋转操作:d=0左转 d=1右转
void rotate(TreapNode* &o, int d) {
TreapNode* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o;
// o成为k的子树 而k的另一个子树没发生变化
// 所以先维护o 在维护k
o->maintain();
k->maintain();
o = k;
}
};

Treap treap;
TreapNode * root = NULL;

int main() {
#if 1
freopen("input.in", "r", stdin);
#endif
//iostream::sync_with_stdio(false);
int t, op, x, y;
rep(i, 1, Maxn) rankArr[i] = rand();
while (scanf("%d" ,&t) != EOF) {
while(t--) {
scanf("%d", &op);
if (op == 0) {
scanf("%d", &x);
treap.insert(root, x);
//cout << "insert: " << x << " size become: " << root->s << endl;
}
else if (op == 1) {
scanf("%d", &x);
if (treap.find(root, x) == 1)
treap.remove(root, x);
else
puts("No Elment!");
}
else if (op == 2) {
scanf("%d%d", &x, &y);
int Rank = treap.rank(root, x);
int Rank2 = root->s - Rank - y + 1;
//cout << "tot: " << root->s << " x: " << x << " rank: " << Rank << endl;
int tmp;
if (Rank2 >= 1 && (tmp = treap.kth(root, Rank2)) != 0)
printf("%d\n", tmp);
else
puts("Not Find!");
}
}
treap.destroy(root);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: