2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。

目录

  • 2023大厂真题提交网址(含题解):
  • 一.前言
  • 二.原理
  • 三.具体实现
  • 四.模板题目
    • 4.1.洛谷P3369:普通平衡树
    • 4.2.洛谷P3391 文艺平衡树
    • 4.3.P3372 线段树 1

一.前言

这个数据结构早有耳闻.只是一直没学.跟着AgOH学了一波.发现很简单.

二.原理

二叉搜索树之所以不够优秀,是因为存在一些数据能够将二叉搜索树退化成一条链.从而导致平方级的复杂度.那么对于这个缺陷,大佬们想出了很多方法去解决,衍生出了①替罪羊树②有旋/无旋Treap③splay.今天我入门学习的就是无旋treap.

Treap之所以能够克服二叉搜索树的缺陷,主要因为它以随机的方式构造二叉搜索树.使得毒瘤数据失效.具体就是将二叉堆和二叉搜索树结合起来.而无旋treap就不需要旋转操作.直接split+merge搞就可以了过程非常像玩拼图.

split有两种方式:按值分裂和按大小分裂.
1.将树分裂成两个部分,左部符合所有值小于等于val,右部符合所有值大于val.
2.将树分裂成两个部分,左部符合子树大小恰好等于val,右部符合大小为补集.

merge的过程很像线段树合并操作.


三.具体实现

说实话搞懂split操作和merge操作,基本就搞懂fhq-treap了.

大概结构:

1.每个节点需要存储:

struct Node
{// 左右儿子,该点的值,该点的优先级,该子树大小.int l , r , val , key , sz;
}fhq[maxn];

2.新建节点操作:

int newnode (int val){fhq[++cnt].val = val;fhq[cnt].key = rnd(); // 复杂度的保证fhq[cnt].sz = 1;return cnt;
}

3.在split/merge后更新节点信息:

void pushup (int x){fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;
}

4.分裂操作:

//注:当前节点在now,以 val为界限分成两部分.左边的父亲节点是x.右边的父亲节点是y.
void split (int now , int val , int &x , int &y)
{if (!now){x = y = 0;return ;}// 代表根和左子树属于集合x.右子树尚未确定,需要继续抽离.if (fhq[now].val <= val){x = now;split(fhq[now].r , val , fhq[now].r , y);}else {// 反之一样.y = now;split(fhq[now].l , val , x , fhq[now].l);}pushup(now);
}

5.合并操作:

//注:将子树x和子树y合并,返回根节点.
// 有个前提条件:子树x的值全严格小于子树y的值,这样才能保证它在合并后还是颗二叉搜索树.
int mer (int x , int y)
{// 任意一个子树为空,返回另一个.两个都为空,返回空.if (!x || !y) return x + y;// 它同时又是一颗二叉堆,满足优先级特点.if (fhq[x].key > fhq[y].key){// x既要作为根,又因为前提,所以y要在x的右下方.fhq[x].r = mer(fhq[x].r , y);pushup(x);return x;}// 反之一样.fhq[y].l = mer(x , fhq[y].l);pushup(y);return y;
}

四.模板题目

4.1.洛谷P3369:普通平衡树

题目地址

fhqTreap可以实现所有其他平衡树能实现的效果.

1.插入数
2.删除 x 数(若有多个相同的数,因只删除一个)
3.查询 x 数的排名(排名定义为比当前数小的数的个数 +1 )
4.查询排名为 x 的数
5.求 x 的前驱(前驱定义为小于 x,且最大的数)
6.求 x 的后继(后继定义为大于 x,且最小的数)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct Node
{int l , r , val , key , sz;
}fhq[maxn];
int cnt , rt;
mt19937 rnd(233);
int newnode (int val){fhq[++cnt].val = val;fhq[cnt].key = rnd();fhq[cnt].sz = 1;return cnt;
}
void pushup (int x){fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;
}
void split (int now , int val , int &x , int &y)
{if (!now){x = y = 0;return ;}if (fhq[now].val <= val){x = now;split(fhq[now].r , val , fhq[now].r , y);}else {y = now;split(fhq[now].l , val , x , fhq[now].l);}pushup(now);
}
int mer (int x , int y)
{if (!x || !y) return x + y;if (fhq[x].key > fhq[y].key){fhq[x].r = mer(fhq[x].r , y);pushup(x);return x;}fhq[y].l = mer(x , fhq[y].l);pushup(y);return y;
}
int x , y , z;
void ins (int val)
{split(rt , val - 1 , x , y);rt = mer(mer(x , newnode(val)) , y);
}
void del (int val)
{split(rt , val - 1, x , z);split(z , val , y , z);y = mer(fhq[y].l , fhq[y].r);rt = mer(mer(x , y) , z);
}
int getrk (int val)
{split(rt , val - 1 , x , y);int res = fhq[x].sz + 1;rt = mer(x , y);return res;
}
int getval (int rk)
{int now = rt;while (now){if (fhq[fhq[now].l].sz == rk - 1) break;if (fhq[fhq[now].l].sz >= rk) now = fhq[now].l;else rk -= fhq[fhq[now].l].sz + 1 , now = fhq[now].r;}return fhq[now].val;
}
int pre (int val)
{split(rt , val - 1 , x , y);int now = x;while (fhq[now].r) now = fhq[now].r;rt = mer(x , y);return fhq[now].val;
}
int aft (int val)
{split(rt , val , x , y);int now = y;while (fhq[now].l) now = fhq[now].l;rt = mer(x , y);return fhq[now].val;
}
int main()
{ios::sync_with_stdio(false);int n; cin >> n;for (int i = 1 ; i <= n ; i++){int op , x; cin >> op >> x;if (op == 1){ins(x);}else if (op == 2){del(x);}else if (op == 3){cout << getrk(x) << endl;}else if (op == 4){cout << getval(x) << endl;}else if (op == 5){cout << pre(x) << endl;}else if (op == 6){cout << aft(x) << endl;}}return 0;
}

4.2.洛谷P3391 文艺平衡树

题目地址
通过这道题目,我们发现fhqTreap同样可以维护区间序列信息.这个时候就是把下标当作节点大小.按子树大小分裂.然后对于任何区间的操作都是将这段区间的子树扣出来进行操作再合并回去.具体看代码.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct Node
{int l , r , val , key , sz;bool re;
}fhq[maxn];
int cnt , rt;
mt19937 rnd(233);
int newnode (int val)
{fhq[++cnt].val = val;fhq[cnt].sz = 1;fhq[cnt].key = rnd();return cnt;
}
void pushup (int x){fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;
}
void pushdown (int x){if (!fhq[x].re) return ;swap(fhq[x].l , fhq[x].r);fhq[x].re = 0;fhq[fhq[x].l].re ^= 1;fhq[fhq[x].r].re ^= 1;return ;
}
// 将now这个子树按sz分成两个部分,sz部分接在x,大于部分接在y
void split (int now , int sz , int &x , int &y)
{if (!now) {x = y = 0;return ;}pushdown(now);if (fhq[fhq[now].l].sz < sz){x = now;split(fhq[now].r , sz - fhq[fhq[now].l].sz - 1 , fhq[now].r , y);}else {y = now;split(fhq[now].l , sz , x , fhq[now].l);}pushup(now);
}
int mer (int x , int y)
{if (!x || !y) return x + y;if (fhq[x].key > fhq[y].key){pushdown(x);fhq[x].r = mer(fhq[x].r , y);pushup(x);return x;}pushdown(y);fhq[y].l = mer(x , fhq[y].l);pushup(y);return y;
}
int x , y , z;
void re (int l , int r)
{split(rt , l - 1 , x , z);split(z , r - l + 1 , y , z);fhq[y].re ^= 1;rt = mer(mer(x , y) , z);
}
void dfs (int now)
{if (!now) return ;pushdown(now);dfs(fhq[now].l);cout << fhq[now].val << " ";dfs(fhq[now].r);return ;
}
int main()
{ios::sync_with_stdio(false);int n , m; cin >> n >> m;for (int i = 1 ; i <= n ; i++){rt = mer(rt , newnode(i));}for (int i = 1 ; i <= m ; i++){int l , r; cin >> l >> r;re(l , r);}dfs(rt);return 0;
}

4.3.P3372 线段树 1

题目地址

类似4.2的做法.每个节点记录一个add标记和sum代表子树的val和.注意pushdown的时候和线段树类似.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct Node
{int l , r , key , sz , add;ll val , sum;
}fhq[maxn];
int cnt , rt;
mt19937 rnd(233);
int newnode (ll val)
{fhq[++cnt].val = val;fhq[cnt].sum = val;fhq[cnt].sz = 1;fhq[cnt].key = rnd();return cnt;
}
void pushup (int x){fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;fhq[x].sum = fhq[fhq[x].l].sum + fhq[fhq[x].r].sum + fhq[x].val;
}
void D (int x , ll c)
{fhq[x].add += c;fhq[x].sum += fhq[x].sz * c;
}
void pushdown (int x){if (!fhq[x].add) return ;fhq[x].val += fhq[x].add;D (fhq[x].l , fhq[x].add);D (fhq[x].r , fhq[x].add);fhq[x].add = 0;return ;
}
// 将now这个子树按sz分成两个部分,sz部分接在x,大于部分接在y
void split (int now , int sz , int &x , int &y)
{if (!now) {x = y = 0;return ;}pushdown(now);if (fhq[fhq[now].l].sz < sz){x = now;split(fhq[now].r , sz - fhq[fhq[now].l].sz - 1 , fhq[now].r , y);}else {y = now;split(fhq[now].l , sz , x , fhq[now].l);}pushup(now);
}
int mer (int x , int y)
{if (!x || !y) return x + y;if (fhq[x].key > fhq[y].key){pushdown(x);fhq[x].r = mer(fhq[x].r , y);pushup(x);return x;}pushdown(y);fhq[y].l = mer(x , fhq[y].l);pushup(y);return y;
}
int x , y , z;
void add (int l , int r , ll v)
{split(rt , l - 1 , x , z);split(z , r - l + 1 , y , z);fhq[y].add += v;rt = mer(mer(x , y) , z);
}
ll ask (int l , int r)
{split(rt , l - 1 , x , z);split(z , r - l + 1 , y , z);ll res = fhq[y].sum;rt =mer(mer(x , y) , z);return res;
}
int main()
{ios::sync_with_stdio(false);int n , m; cin >> n >> m;for (int i = 1 ; i <= n ; i++){int x; cin >> x;rt = mer(rt , newnode(x));}for (int i = 1 ; i <= m ; i++){int op , x , y , k; cin >> op;if (op == 1){cin >> x >> y >> k;add(x , y , k);}else {cin >> x >> y;cout << ask(x , y) << endl;}}return 0;
}

fhq treap入门相关推荐

  1. P2596 [ZJOI2006]书架(fhq treap)

    P2596 [ZJOI2006]书架 我们用fhq treap来完成这一题 对于一个新插入的节点我们取权值为其索引值,其所记录的valuevaluevalue是其当前索引所在位置. 操作一:把索引为v ...

  2. 可持久化平衡树(FHQ Treap)

    两个最基本的操作 merge合并 split分割 merge 把两棵treap合并成一棵treap,要满足T1最大值要比T2最小值小,比较将随机数值key值更大的作为合并后的根 假设T1作为根节点作为 ...

  3. FHQ Treap 详解

    0. 简单介绍 FHQ Treap,以下简写为fhq,是一种treap(树堆)的变体,功能比treap强大,代码比splay好写,易于理解,常数稍大. fhq不需要通过一般平衡树的左右旋转来保持平衡, ...

  4. FHQ Treap 总结

    [前言(一堆废话)] 目前 OI 竞赛中两大主流平衡树之一就是 FHQ Treap(另一个是 Splay). 普通 BST 的中序遍历中,val 值构成一个单调递增的序列. Treap 在 BST 的 ...

  5. Treap + FHQ Treap

    一:Treap 支持:插入.删除.查询 x x x 的排名.查询排名为 x x x 的数.查前驱.查后继.左旋右旋 模板题:P3369 [模板]普通平衡树 #include<bits/stdc+ ...

  6. 平衡树学习笔记之 fhq Treap

    平衡树学习笔记 1:fhq Treap(非旋 Treap) 正文开始前首先 %%% fhq 大佬. 众所周知,平衡树是一种 非常猥琐 码量堪忧的数据结构. 他的祖先是一种叫做二叉搜索树 ( B S T ...

  7. FHQ TREAP 学习总结

    F H Q T R E A P FHQ \ TREAP FHQ TREAP P r e p a r e K n o w l e d g e Prepare \ Knowledge Prepare Kn ...

  8. 【模板】FHQ Treap

    FHQ Treap 无旋Treap 维护的信息 c h [ i ] [ 0 / 1 ] ch[i][0/1] ch[i][0/1] v a l [ i ] val[i] val[i] f i x [ ...

  9. FHQ Treap【基于P3369的讲解】【随机数、各数组、函数运用】

    该模板题的题目链接 很多人看到了FHQ Treap都不知道它是干什么用的,今天也是刚学的FHQ Treap,学了一整天了,终于过掉了洛谷的P3369了,也算是对这个算法有了些自己的了解,还是错的太多次 ...

最新文章

  1. html设置根rem,经过js动态设置根元素的rem方案
  2. 实现控制台上的进度条
  3. [编程入门]宏定义之闰年判断:给年份year,定义一个宏,以判别该年份是否闰年。提示:宏名可以定义为LEAP_YEAR,形参为y,既定义宏的形式为 #define LEAP_YEAR(y) (读者设计
  4. 第34课 生命周期与素数 《小学生C++趣味编程》
  5. 快速安装 Moodle 指南
  6. linux6.3 dhcp,51CTO博客-专业IT技术博客创作平台-技术成就梦想
  7. linux内核:__user,__kernel,__safe,__force,__iomem
  8. ilm 和dlm差异_Oracle 的信息生命周期管理工具(ILM assistant)
  9. 在ubuntu系统下cocos2dx移植到android平台
  10. 九度OJ 1037:Powerful Calculator(强大的计算器) (大整数运算)
  11. Android中Fragment生命周期和基本用法
  12. Hibernate(转载)
  13. 浅谈网页压缩GZIP
  14. Mac 中如何解压.bin文件
  15. free-mybatis-plugin插件下载
  16. Nacos的连接拒接丶解决方案
  17. 基于微信小程序的评分小程序
  18. 离婚案件中有贷款及增值房产的分割方法
  19. UPlayer播放器问题相关
  20. OSPF prefix-suppression Test

热门文章

  1. 前端实现浏览器自动弹开三屏、一键关闭效果
  2. 广州大学纺织服装学院计算机应用,广州大学纺织服装学院代码是多少
  3. php短网址生成代码,一个php短网址的生成代码(仿微博短网址)
  4. assign 组合逻辑和always@(*)组合逻辑的区别
  5. 电路中的开漏输出与推挽输出
  6. ControllerRevision
  7. 归并排序(C语言简单实现)
  8. SAR+L波段+森林生物量估计+高度反演
  9. jenkins忘记账号密码,元芳,你怎么看?
  10. java 微信公众号之授权登录