BZOJ 1208 宠物饲养所 Splay
要实现的操作是插入,删除,找到比指定值大的,小的值操作。
Splay的删除操作可以是直接用二叉搜索树的删除方式,或者是先将要删除的节点Splay到根,然后找到左子树中最大的节点,将其Splay到根的左儿子位置,此时这个节点必然是没有右子树的,然后直接把他当做根就好。
找大的值可以先找到如果要插入这个值会插在哪里,然后不执行操作,直接找前驱或者后继就可以了。
代码能力捉急,写了整整一天,各种debug蛋疼啊= =
#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;
const int maxn = 2e6 + 10;
const int mod = 1000000;
const int PET = 0;
const int HUMAN = 1;
const int EMPTY = -1;
const int INF = INT_MAX / 3;
int ch[maxn][2], fa[maxn], val[maxn], sz, root;
void rotate(int x, int d) {
int y = fa[x];
ch[y][d ^ 1] = ch[x][d];
fa[ch[x][d]] = y;
if (fa[y] != 0) {
ch[fa[y]][y == ch[fa[y]][1]] = x;
}
ch[x][d] = y;
fa[x] = fa[y];
fa[y] = x;
}
int newNode(int &r, int father, int v) {
r = ++sz;
fa[r] = father; val[r] = v;
ch[r][0] = ch[r][1] = 0;
return r;
}
void splay(int x, int goal) {
while (fa[x] != goal) {
int y = fa[x], d = val[x] > val[y];
if (fa[y] == goal) {
rotate(x, d ^ 1);
break;
}
int z = fa[y], d1 = val[y] > val[z];
if (d == d1) {
rotate(y, d1 ^ 1);
rotate(x, d ^ 1);
}
else {
rotate(x, d ^ 1);
rotate(x, d1 ^ 1);
}
}
if (goal == 0) {
fa[x] = 0;
root = x;
}
}
void debug(int root) {
int lc = ch[root][0], rc = ch[root][1];
printf("当前节点:%d(val = %d), lch: %d(val = %d), rch %d(val = %d), fa is %d\n",
root, val[root], lc, val[lc], rc, val[rc], fa[root]);
if (lc) debug(lc);
if (rc) debug(rc);
}
int insert(int v) {
if (root == 0) {
newNode(root, 0, v);
return root;
}
int u = root;
while (ch[u][v > val[u]] != 0)
u = ch[u][v > val[u]];
int r = newNode(ch[u][v > val[u]], u, v);
splay(r, 0);
return r;
}
//找后继
int findNext(int x) {
//如果x节点有右子树
if (ch[x][1] != 0) {
//找到右子树中最小的节点
int u = ch[x][1];
while (ch[u][0] != 0) u = ch[u][0];
return u;
}
//往上寻找
int u = x;
while (fa[u] != 0 && u != ch[fa[u]][0]) u = fa[u];
return fa[u];
}
//用二叉搜索树删除节点的方式来删除节点
void remove(int x) {
if (ch[x][0] == 0 && ch[x][1] == 0) {
if (fa[x] == 0) root = 0;
else ch[fa[x]][x == ch[fa[x]][1]] = 0;
}
else if (ch[x][0] == 0) {
if (fa[x] == 0) {
root = ch[x][1];
fa[ch[x][1]] = 0;
}
else ch[fa[x]][x == ch[fa[x]][1]] = ch[x][1];
fa[ch[x][1]] = fa[x];
}
else if (ch[x][1] == 0) {
if (fa[x] == 0) {
root = ch[x][0];
fa[ch[x][0]] = 0;
}
else ch[fa[x]][x == ch[fa[x]][1]] = ch[x][0];
fa[ch[x][0]] = fa[x];
}
else {
int r = findNext(x);
swap(val[r], val[x]);
remove(r);
}
}
//先splay到根然后删除
void remove_root() {
int u = root;
if (ch[u][0] == 0) {
root = ch[u][1];
fa[ch[u][1]] = 0;
}
else {
//找到左子树中最大的值
int x = ch[u][0];
while (ch[x][1] != 0) x = ch[x][1];
//splay到根的做子树
splay(x, root);
//debug(root);
//此时x必然没有右子树,直接作为根
ch[x][1] = ch[u][1];
if (ch[u][1]) fa[ch[u][1]] = x;
root = x; fa[x] = 0;
}
//debug(root);
}
int findValMinNext(int v) {
int u = root;
while (ch[u][v > val[u]] != 0) u = ch[u][v > val[u]];
if (v >= val[u]) return u;
while (fa[u] != 0 && val[fa[u]] > val[u]) u = fa[u];
return fa[u];
}
int findValMaxNext(int v) {
int u = root;
while (ch[u][v > val[u]] != 0) u = ch[u][v > val[u]];
if (v < val[u]) return u;
while (fa[u] != 0 && val[fa[u]] <= val[u]) u = fa[u];
return fa[u];
}
int main() {
//freopen("INPUT.002", "r", stdin);
//freopen("out.txt", "w", stdout);
int n, state, cmd, st, ans;
while (scanf("%d", &n) != EOF) {
sz = root = ans = 0;
state = EMPTY;
for (int i = 1; i <= n; i++) {
//debug(root);
scanf("%d%d", &cmd, &st);
if (state == EMPTY) {
state = cmd; insert(st);
}
else if (state == cmd) insert(st);
else {
val[0] = INF;
int g1 = findValMinNext(st), g2 = findValMaxNext(st);
//run_test();
//printf("g1 is %d, g2 is %d\n", val[g1], val[g2]);
int v1 = abs(st - val[g1]), v2 = abs(st - val[g2]);
if (v1 <= v2) {
ans = (ans + v1) % mod;
splay(g1, 0);
remove(root);
//debug(root);
//remove_root();
}
else {
ans = (ans + v2) % mod;
splay(g2, 0);
//debug(root);
remove(root);
//remove_root();
}
if (root == 0) state = EMPTY;
}
}
printf("%d\n", ans);
}
return 0;
}

浙公网安备 33010602011771号