P5076二叉搜索树求调,一直爆MLE
  • 板块学术版
  • 楼主Stevehim
  • 当前回复0
  • 已保存回复0
  • 发布时间2022/10/22 22:43
  • 上次更新2023/10/27 06:24:29
查看原帖
P5076二叉搜索树求调,一直爆MLE
759274
Stevehim楼主2022/10/22 22:43
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <string>
#define maxn 1000010
using namespace std;
const int INF = 0x7fffffff;

//自制 二叉平衡树
struct node {
	int ls = -1;
	int rs = -1;
	int val;
	int size;
	int cnt;
} x[maxn];
int bnt = 0;
int a;

int check(int v, int num) { //防止递归所做的努力
	/*
	0代表相等
	11代表大于且无左子树,12代表大于且有左子树
	21代表小于且无右子树,22代表小于且有右子树
	*/
	if (x[num].val == v) { //如果值相等
		return 0;
	}
	if (x[num].val > v) { //如果这个节点的值大于给的值,说明需要走左边
		if (x[num].ls == -1) { //这里与日报不一样,我检测有没有子树
			return 11;
		} else {
			return 12;
		}
	} else { //如果这个节点的值小于给的值,走右边
		if (x[num].rs == -1) { //这里与日报不一样,我检测有没有子树
			return 21;
		} else {
			return 22;
		}
	}
}

void add(int v, int num = 0) { //num表示当前有值的结点的的序号,v表示添加的值
	if (bnt == 0) { //检测bnt,事实上日报恰恰少了这一步
		x[bnt].val = v;
		x[bnt].size = 1;
		x[bnt].cnt = 1;
		bnt++;
		return; //根节点创建完成,退出
	} else { //不是
		x[num].size++;
		while (1) {
			a = check(v, num);
			switch (a) {
				case 0: {
					x[num].cnt++; //计数器++
					return;
				}
				case 11: {
					x[bnt].val = v;
					x[bnt].size = 1;
					x[bnt].cnt = 1;
					x[num].ls = bnt; //建立关系
					bnt++;
					break;
				}
				case 12: {
					num = x[num].ls;
					break;
				}
				case 21: {
					x[bnt].val = v;
					x[bnt].size = 1;
					x[bnt].cnt = 1;
					x[num].rs = bnt; //建立关系
					bnt++;
					break;
				}
				case 22: {
					num = x[num].rs;
					break;
				}
			}
		}
		return;
	}
}

int GetPre(int num, int v, int ans) { //num表示将要进行比较的结点,v表示需要查找的,ans表示备份的答案
	if (x[num].val >= v) {
		if (x[num].ls == -1) {
			return ans; //返回答案备份
		} else {
			return GetPre(x[num].ls, v, ans);
		}
	} else {
		if (x[num].rs == -1) {
			return x[num].val;
		} else {
			return GetPre(x[num].rs, v, x[num].val);
		}
	}
}

int GetNext(int num, int v, int ans) { //num表示将要进行比较的结点,v表示需要查找的,ans表示备份的答案
	if (x[num].val <= v) {
		if (x[num].rs == -1) {
			return ans; //返回答案备份
		} else {
			return GetNext(x[num].rs, v, ans);
		}
	} else {
		if (x[num].ls == -1) {
			return x[num].val;
		} else {
			return GetNext(x[num].ls, v, x[num].val);
		}
	}
}

int root_size = x[0].size - x[x[0].rs].size;

int GetValByRank(int num, int rank) { //num指当前比较的结点,rank指排名
	if (rank == 0) {
		return INF;
	}
	if (rank == root_size) {
		return x[0].val;
	}
	if (x[x[num].ls].size >= rank) { //先查看普遍值偏小的子树的大小是否足够排名了
		return GetValByRank(x[num].ls, rank); //跑到左子树的左子树里面查
	}
	if (x[x[num].ls].size + x[num].cnt >= rank) { //左子树与我当前这个结点有的个数的值加起来大于它
		return x[num].val; //直接返回吧
	}
	return GetValByRank(x[num].rs, rank - x[x[num].ls].size - x[num].cnt);
}

int GetRankByVal(int num, int val) { //变量意义参上
	if (val == x[num].val) {
		return x[x[num].ls].size + 1;
	}
	if (val < x[num].val) {
		return GetRankByVal(x[num].ls, val);
	}
	return GetRankByVal(x[num].rs, val) + x[x[num].ls].size + x[num].cnt;
}


int q, opt, x1;

int main() {
	cin >> q;
	for (int i = 0; i < q; i++) {
		cin >> opt >> x1;
		switch (opt) {
			case 1: {
				cout << GetRankByVal(0, x1) << endl;
				break;
			}
			case 2: {
				cout << GetValByRank(0, x1) << endl;
				break;
			}
			case 3: {
				cout << GetPre(0, x1, -INF) << endl;
				break;
			}
			case 4: {
				cout << GetNext(0, x1, INF) << endl;
				break;
			}
			case 5: {
				add(x1);
				break;
			}
		}
	}
	return 0;
}

2022/10/22 22:43
加载中...