Treap树入门练习题目,此题主要来练习Treap的操作
此题也是刘汝佳 大白书,Treap的例题
用指针实现的Treap的操作
注意:
1.不要访问NULL
2.cmp函数的使用,相等时返回-1
其它,待补充。。。
另:
为避免错误和是操作的简洁,可使用一个真实的空指针null代替空指针NULL,。。。
关于内存预申请的优化写法,待补充
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i >= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(a, v) memset(a, v, sizeof(a))
#define PB push_back
#define MP make_pair
typedef long long LL;
const int INF = 0x3f3f3f3f;
struct Node {
Node *ch[2];
int r; ///随机优先级
int v; ///值
int s; ///节点总数
Node(int v) : v(v) { ch[0] = ch[1] = NULL; r = rand(); s = 1; }///
bool operator < (const Node &rhs) const {
return r < rhs.r;
}
int cmp(int x) const {
if (x == v) return -1;
return x < v ? 0 : 1;
}
void pushup() {
s = 1;
if (ch[0] != NULL) s += ch[0]->s;
if (ch[1] != NULL) s += ch[1]->s;
}
};
///不用确保o有孩子节点吗?
void rotate(Node* &o, int d) {
Node* k = o->ch[d ^ 1];
o->ch[d ^ 1] = k->ch[d]; k->ch[d] = o;
o->pushup(); k->pushup(); ///先o后k
o = k;
}
void insert(Node* &o, int x) {
if (o == NULL) o = new Node(x);
else {
int d = (x < o->v ? 0 : 1);///不要用cmp函数,可能有相同节点
insert(o->ch[d], x);
if (o->ch[d] > o) rotate(o, d ^ 1);
}
o->pushup();
}
void remove(Node* &o, int x) {
int d = o->cmp(x);
if (d == -1) {
Node* u = o;
if (o->ch[0] != NULL && o->ch[1] != NULL) {
int d2 = (o->ch[0] > o->ch[1] ? 1 : 0);
rotate(o, d2); remove(o->ch[d2], x);
} else {
if (o->ch[0] == NULL) o = o->ch[1];
else o = o->ch[0];
delete u; ///!!!
}
}
else remove(o->ch[d], x);
if (o != NULL) o->pushup();
}
const int maxc = 500000 + 10;
const int maxn = 20000 + 10;
const int maxm = 60000 + 10;
struct Command {
char type;
int x, p;
Command(){}
Command(char type, int x, int p) : type(type), x(x), p(p){}
}Q[maxc];
int n, m;
int weight[maxn];
int from[maxm], to[maxm], removed[maxm];
///并查集相关
int fa[maxn];
void init_fa(int n) {
REP(i, n + 1) fa[i] = i;
}
int findset(int x) {
return fa[x] == x ? x : fa[x] = findset(fa[x]);
}
/// 名次树相关
Node* root[maxn];
///查第k大
int kth(Node* 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 (k == s + 1) return o->v;
if (k <= s) return kth(o->ch[1], k);
else return kth(o->ch[0], k - s - 1);
}
void mergeto(Node* &src, Node* &dest) {
if (src->ch[0] != NULL) mergeto(src->ch[0], dest);
if (src->ch[1] != NULL) mergeto(src->ch[1], dest);
insert(dest, src->v);///
delete(src); src = NULL;
}
void removetree(Node* &o) {
if (o->ch[0] != NULL) removetree(o->ch[0]);
if (o->ch[1] != NULL) removetree(o->ch[1]);
delete(o); o = NULL;
}
///主程序相关
void add_edge(int x) {
int u = findset(from[x]), v = findset(to[x]);
if (u != v) {
if (root[u]->s < root[v]->s) {
fa[u] = v;
mergeto(root[u], root[v]);
}
else {
fa[v] = u;
mergeto(root[v], root[u]);
}
}
}
int Q_cnt;
LL Q_tot;
void query(int x, int k) {
Q_cnt++;
Q_tot += kth(root[findset(x)], k);
}
void change_weight(int x, int v)
{
int u = findset(x);
remove(root[u], weight[x]);
insert(root[u], v);
weight[x] = v;
}
int nc;
void solve(int c) {
Q_tot = Q_cnt = 0;
for (int i = c - 1; i >= 0; i--) {
if (Q[i].type == 'D') add_edge(Q[i].x);
else if (Q[i].type == 'Q') query(Q[i].x, Q[i].p);
else change_weight(Q[i].x, Q[i].p);
}
printf("Case %d: %.6lf\n", nc++, Q_tot / (1.0 * Q_cnt));
}
int main () {
nc = 1;
while (scanf("%d%d", &n, &m) == 2 && n) {
for (int i = 1; i <= n; i++) scanf("%d", &weight[i]);
for (int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]);
CLR(removed, 0);
int c = 0;
while (1) {
char type;
int x, p = 0, v = 0;
scanf(" %c", &type);
if (type == 'E') break;
scanf("%d", &x);
if (type == 'D') removed[x] = 1;
if (type == 'Q') scanf("%d", &p);
if (type == 'C') {
scanf("%d", &v);
p = weight[x];///
weight[x] = v;
}
Q[c++] = Command(type, x, p);
}
///最终图
init_fa(n);
for (int i = 1; i <= n; i++) {
if (root[i] != NULL) removetree(root[i]);
root[i] = new Node(weight[i]);
}
for (int i = 1; i <= m; i++) {
if (!removed[i]) add_edge(i);
}
///反向操作
solve(c);
}
return 0;
}
使用了null的代码:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i >= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(a, v) memset(a, v, sizeof(a))
#define PB push_back
#define MP make_pair
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = 100010;
struct Node{
Node *ch[2];
int r, v, s;
Node(){}
Node(int v, Node *null):v(v){ ch[0] = ch[1] = null; s = 1; r = rand(); }
int cmp(int x)
{
if (v == x) return -1;
return x < v ? 0 : 1;
}
void maintain()
{
s = ch[0]->s + ch[1]->s + 1;
}
bool operator<(const Node& rhs) const
{
return r < rhs.r;
}
}*null;
void rotate(Node* &rt, int d)
{
Node* k = rt->ch[d ^ 1]; rt->ch[d ^ 1] = k->ch[d]; k->ch[d] = rt;
rt->maintain(); k->maintain(); rt = k;
}
void insert(Node* &rt, int x)
{
if (rt == null) { rt = new Node(x, null); }
else
{
int d = x < rt->v ? 0 : 1;
insert(rt->ch[d], x);
if (rt < rt->ch[d]) rotate(rt, d ^ 1);
}
rt->maintain();
}
void remove(Node* &rt, int x)
{
int d = rt->cmp(x);
if (d == -1)
{
Node* u = rt;
if (rt->ch[0] != null && rt->ch[1] != null)
{
int d2 = rt->ch[0] > rt->ch[1] ? 1 : 0;
rotate(rt, d2);
remove(rt->ch[d2], x);
}
else
{
if (rt->ch[0] == null) rt = rt->ch[1];
else rt = rt->ch[0];
delete(u);
}
}
else remove(rt->ch[d], x);
if (rt != null) rt->maintain();
}
const int maxc = 500000 + 10;
const int maxn = 20000 + 10;
const int maxm = 60000 + 10;
///名次树相关
Node *root[maxn];
void init_root()
{
null = new Node();
null->ch[0] = null->ch[1] = null;
null->r = null->v = null->s = 0;
for (int i= 0; i < maxn; i++) root[i] = null;
}
int kth(Node *rt, int k)
{
if (rt == null || k <= 0 || k > rt->s) return 0;
// int ss = rt->ch[1] == null ? 0 : rt->ch[1]->s;///!!!
int ss = rt->ch[1]->s;
if (k == ss + 1) return rt->v;
else if (k < ss + 1) return kth(rt->ch[1], k);
else return kth(rt->ch[0], k - ss - 1);
}
void mergeto(Node* &src, Node* &dest)
{
if (src->ch[0] != null) mergeto(src->ch[0], dest);
if (src->ch[1] != null) mergeto(src->ch[1], dest);
insert(dest, src->v);
delete src;
src = null;
}
void removetree(Node* &rt)
{
if (rt->ch[0] != null) removetree(rt->ch[0]);
if (rt->ch[1] != null) removetree(rt->ch[1]);
delete rt;
rt = null;
}
struct Query{
char op;
int x, p;
Query(){}
Query(char op, int x, int p) : op(op), x(x), p(p) {}
}Q[maxc];
int Q_cnt;
long long Q_sum;
int cnt;
int n, m;
int val[maxn];
int from[maxm], to[maxm];
bool removed[maxm];
///并查集相关
int fa[maxn];
void init_fa(int n)
{
for (int i = 0; i <= n; i++) fa[i] = i;
}
int find_set(int x)
{
return x == fa[x] ? fa[x] : fa[x] = find_set(fa[x]);
}
///main相关
void add_edge(int i)
{
int x = from[i], y = to[i];
int fax = find_set(x), fay = find_set(y);
if (fax != fay)
{
if (root[fax]->s < root[fay]->s) ///!!!注意
{
fa[fax] = fay;
mergeto(root[fax], root[fay]);
}
else
{
fa[fay] = fax;
mergeto(root[fay], root[fax]);
}
}
}
void change(int i, int p)
{
int fai = find_set(i);
remove(root[fai], val[i]);
val[i] = p;
insert(root[fai], val[i]);
}
void query(int i, int p)
{
int fai = find_set(i);
Q_cnt++;
Q_sum += kth(root[fai], p);
}
int main ()
{
init_root();
int nc = 1;
while (scanf("%d%d", &n, &m) != EOF && n + m)
{
init_fa(n);
CLR(removed, 0);
for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
for (int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]);
char op;
int x, p;
cnt = 0;
while (~scanf(" %c", &op) && op != 'E')
{
scanf("%d", &x);
if (op == 'D') removed[x] = 1;
else if (op == 'Q') scanf("%d", &p);
else if (op == 'C')
{
scanf("%d", &p);
swap(val[x], p);
}
Q[cnt++] = Query(op, x, p);
}
for (int i = 1; i <= n; i++)
{
if (root[i] != null) removetree(root[i]);
root[i] = new Node(val[i], null);
}
for (int i = 1; i <= m; i++)
{
if (!removed[i]) add_edge(i);
}
Q_cnt = Q_sum = 0;
for (int i = cnt - 1; i >= 0; i--)
{
if (Q[i].op == 'D') add_edge(Q[i].x);
else if (Q[i].op == 'Q') query(Q[i].x, Q[i].p);
else if (Q[i].op == 'C') change(Q[i].x, Q[i].p);
}
printf("Case %d: %.6lf\n", nc++, Q_sum / (double)Q_cnt);
}
return 0;
}