ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 洛谷 P3369 【模板】普通平衡树

2021-05-23 15:03:00  阅读:152  来源: 互联网

标签:洛谷 val int 题解 son P3369 return wh size


普通平衡树模板题,这里我写的是 Treap 。

Treap 大概是最最最基本的平衡树了吧(基本上就是 BST 上加了个堆性质)

关于 Treap 的坑点:

  1. 哪里都不能丢的 update :只要你的操作涉及父子关系的修改,就不要忘记更新子树大小。
  2. 代码简化:用 \(son[i][0/1]\) 存储左右儿子而非 \(ls[i]\) 和 \(rs[i]\) (对旋转操作的简化显著)。
  3. 维护堆性质:修改父子关系时,一定要保证以随机权值为关键字的堆性质。
  4. 细节:各种细节,每一个都可能大大加长你的调试时间(本蒻蒻因少写一个 update 调了一天QAQ)。

具体实现就见代码了吧:(说实话这类数据结构画出图来非常生动形象,就是代码难写)


#include <bits/stdc++.h>

#define Rei register int
#define ll long long

using namespace std;

const int inf = 0x3f3f3f3f;
const int N = 1e5+5;

template<typename T>
inline void read(T &x) {
	x = 0;
	char f = 0, c = getchar();
	while(!isdigit(c)) f |= (c=='-'), c = getchar();
	if(f) while(isdigit(c)) x = x*10-c+48, c = getchar();
	else while(isdigit(c)) x = x*10+c-48, c = getchar();
}

int n;

struct treap {
	int tot, root;
	int val[N], QAQ[N], cnt[N], size[N];
	int son[N][2];
	
	int new_node(int v) {
		val[++tot] = v, cnt[tot] = size[tot] = 1, QAQ[tot] = rand();
		return tot;
	}
	
	void update(int p) {
		size[p] = size[son[p][0]] + size[son[p][1]] + cnt[p];
	}
	
	void rotate(int &p, int wh) {
		int q = son[p][wh];
		son[p][wh] = son[q][wh^1], son[q][wh^1] = p, p = q;
		update(son[p][wh^1]), update(p);
	}
	
	void insert(int &p, int v) {
		if(p == 0) {
			p = new_node(v);
			return;
		}
		if(v == val[p]) {
			++cnt[p], update(p);
			return;
		} 
		int wh = v > val[p];
		insert(son[p][wh], v);	
		QAQ[son[p][wh]] > QAQ[p]? rotate(p, wh):update(p);
	}

	void remove(int &p, int v) {
		if(!p) return;
		if(v == val[p]) {
			if(cnt[p]>1) --cnt[p], update(p);
			else if(!son[p][0] && !son[p][1]) p = 0;
			else {
				if(!son[p][1] || QAQ[son[p][0]] > QAQ[son[p][1]]) rotate(p, 0), remove(son[p][1], v);
				else rotate(p, 1), remove(son[p][0], v);
				update(p);
			}
			return;
		}
		int wh = v > val[p];
		remove(son[p][wh], v);
		update(p);
	}
	
	int get_rank(int p, int v) {
		if(v == val[p]) return size[son[p][0]] + 1;
		if(v < val[p]) return get_rank(son[p][0], v);
		return size[son[p][0]] + cnt[p] + get_rank(son[p][1], v);
	}
	
	int get_val(int p, int rank) {
		if(size[son[p][0]] + 1 > rank) return get_val(son[p][0], rank);
		if(size[son[p][0]] + cnt[p] >= rank) return val[p];
		return get_val(son[p][1], rank - size[son[p][0]] - cnt[p]);
	}
	
	int get_qian(int v) {
		int p = root, ans;
		while(p) {
			if(val[p] < v) ans = val[p], p = son[p][1];
			else p = son[p][0];
		}
		return ans;
	}
	
	int get_hou(int v) {
		int p = root, ans;
		while(p) {
			if(val[p] > v) ans = val[p], p = son[p][0];
			else p = son[p][1];
		}
		return ans;
	}
} phs;

int main() {
	srand(time(0));
	read(n);
	int opt, x;
	for(Rei i = 1; i <= n; ++i) {
		read(opt), read(x);
		switch(opt) {
			case 1: phs.insert(phs.root, x); break;
			case 2: phs.remove(phs.root, x); break;
			case 3: printf("%d\n", phs.get_rank(phs.root, x)); break;
			case 4: printf("%d\n", phs.get_val(phs.root, x)); break;
			case 5: printf("%d\n", phs.get_qian(x)); break;
			case 6: printf("%d\n", phs.get_hou(x)); break;
		}
	}
	return 0;
}

希望能对你有帮助!(*/ω\*)

标签:洛谷,val,int,题解,son,P3369,return,wh,size
来源: https://www.cnblogs.com/Szzkp/p/14801170.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有