pb_ds库实现支持多个相同的值的名次树

阅读量: searchstar 2019-06-30 19:37:05
Categories: Tags:

参考的大佬的博客的链接:
https://blog.csdn.net/onepointo/article/details/75083305

//luogu_3369
#include <stdio.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

typedef long long LL;

tree<LL, null_type, less<LL>, rb_tree_tag, tree_order_statistics_node_update> t;
map<int, int> ma;
void Insert(int v) {
t.insert(((LL)v << 32) + ++ma[v]);
}

void Delete(int v) {
auto it = ma.find(v);
t.erase(((LL)v << 32) + it->second);
--it->second;
if (0 == it->second) {
ma.erase(it);
}
}

int RankOf(int v) {
return t.order_of_key((LL)v << 32) + 1;
}

int FindByRank(int r) {
return *t.find_by_order(r-1) >> 32;
}

int FindPre(int v) {
auto it = ma.lower_bound(v);
--it;
return it->first;
}

int FindNext(int v) {
return ma.upper_bound(v)->first;
}

int main() {
int n;
scanf("%d", &n);
while (n--) {
int op, x;
scanf("%d%d", &op, &x);
switch (op) {
case 1:
Insert(x);
break;
case 2:
Delete(x);
break;
case 3:
printf("%d\n", RankOf(x));
break;
case 4:
printf("%d\n", FindByRank(x));
break;
case 5:
printf("%d\n", FindPre(x));
break;
case 6:
printf("%d\n", FindNext(x));
break;
}
}
return 0;
}

注意如果less<LL>不小心写成了less<int>,编译器不会报错,但是答案是错的。

另一种不用map来求前驱和后继的比较和谐的方法:

//luogu_3369
#include <stdio.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

typedef long long LL;

tree<LL, null_type, less<LL>, rb_tree_tag, tree_order_statistics_node_update> t;
map<int, int> ma;
void Insert(int v) {
t.insert(((LL)v << 32) + ++ma[v]);
}

void Delete(int v) {
t.erase(((LL)v << 32) + ma[v]--);
}

int RankOf(int v) {
return t.order_of_key((LL)v << 32) + 1;
}

int FindByRank(int r) {
return *t.find_by_order(r-1) >> 32;
}

int FindPre(int v) {
auto it = t.lower_bound((LL)v << 32);
--it;
return *it >> 32;
}

int FindNext(int v) {
return *t.lower_bound((LL)(v+1) << 32) >> 32;
}

int main() {
int n;
scanf("%d", &n);
while (n--) {
int op, x;
scanf("%d%d", &op, &x);
switch (op) {
case 1:
Insert(x);
break;
case 2:
Delete(x);
break;
case 3:
printf("%d\n", RankOf(x));
break;
case 4:
printf("%d\n", FindByRank(x));
break;
case 5:
printf("%d\n", FindPre(x));
break;
case 6:
printf("%d\n", FindNext(x));
break;
}
}
return 0;
}

封装版:

//luogu_3369
#include <stdio.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

template<typename T, typename less>
struct Cmp_MultiSet {
bool operator () (const pair<T, size_t>& x, const pair<T, size_t>& y) const {
return less()(x.first, y.first) ? true : (less()(y.first, x.first) ? false : less()(x.second, y.second));
}
};

template<typename T, typename less>
struct MultiSet {
tree<pair<T, size_t>, null_type, Cmp_MultiSet<T, less>, rb_tree_tag, tree_order_statistics_node_update> t;
map<T, size_t> ma;
void Insert(T v) {
t.insert(make_pair(v, ++ma[v]));
}
void Delete(T v) {
t.erase(make_pair(v, ma[v]--));
}
size_t RankOf(T v) {
return t.order_of_key(make_pair(v, 0)) + 1;
}
T FindByRank(size_t r) {
return t.find_by_order(r-1)->first;
}
T FindPre(T v) {
auto it = t.lower_bound(make_pair(v, 0));
return (--it)->first;
}
T FindNext(T v) {
return t.lower_bound(make_pair(v+1, 0))->first;
}
};

int main() {
MultiSet<int, less<int> > se;
int n;
scanf("%d", &n);
while (n--) {
int op, x;
scanf("%d%d", &op, &x);
switch (op) {
case 1:
se.Insert(x);
break;
case 2:
se.Delete(x);
break;
case 3:
printf("%lu\n", se.RankOf(x));
break;
case 4:
printf("%d\n", se.FindByRank(x));
break;
case 5:
printf("%d\n", se.FindPre(x));
break;
case 6:
printf("%d\n", se.FindNext(x));
break;
}
}
return 0;
}