模板:无旋treap
文章目录
- 前言
- 操作
- 合并
- 分裂
- 插入
- 删除
- 查找第k大
- 查询x的排名
- 前驱后继
- 完整代码
所谓无旋treap,就是不带旋转的treap
前言
现在“理论上”我会四种平衡树了
之前说无旋treap功能弱,是我狗眼看银低了qwq
这玩意区间上该搞的也能搞
而且确实是非常的 好写!!
有点想把这个作为默认项了
呜呜呜朝三暮四肿么办呐
操作
关键是合并和分裂
合并
考虑合并u和v两棵子树
把优先级高的作为根
剩下的接着合并即可
il int merge(int u,int v){if(!u) return v;if(!v) return u;if(tr[u].key>tr[v].key){tr[u].rs=merge(tr[u].rs,v);pushup(u);return u;}else{tr[v].ls=merge(u,tr[v].ls);pushup(v);return v;}
}
分裂
给定一个val
<=val的归一棵,>=val的归另一棵
讨论一些根归谁
然后递归一下即可
如果要求前k个一棵是一个道理
il void split(int x,int v,int &L,int &R){if(!x){L=R=0;return;}if(tr[x].val<=v){L=x;split(tr[L].rs,v,tr[L].rs,R);pushup(L);}else{R=x;split(tr[R].ls,v,L,tr[R].ls);pushup(R);}return;
}
插入
插入一个为v的元素
把树按照v掰成两个
把开的新点merge上去即可
il void ins(int v){int a(0),b(0),c(0);split(r,v,a,b);c=New(v);r=merge(merge(a,c),b);return;
}
删除
删除一个v
先把<=v的split出来
再把<v的split出来
剩下的全是=v的
把其左右子树合并就相当于扣掉一个
最后merge回去就行
il void del(int v){int a(0),b(0),c(0);split(r,v,a,b);split(a,v-1,a,c);r=merge(merge(a,merge(tr[c].ls,tr[c].rs)),b);
}
查找第k大
BST常规操作
il int findnth(int kth){//printf("findnth:%d\n",kth);int x=r;while(1){//printf("x=%d val=%d siz=%d ls=%d rs=%d\n",x,tr[x].val,tr[x].siz,tr[x].ls,tr[x].rs);if(kth<=tr[tr[x].ls].siz) x=tr[x].ls;else if(kth==tr[tr[x].ls].siz+1) return tr[x].val;else{kth-=tr[tr[x].ls].siz+1;x=tr[x].rs;}}
}
查询x的排名
这个用常规的BST的操作是 不行 的!
因为树上存在这权值相同的点
但可以直接把<x的split出来查询siz
也很方便
最后记得要merge回去!
il int findrnk(int v){int a(0),b(0),c(0),res;split(r,v-1,a,b);res=tr[a].siz;r=merge(a,b);return res+1;
}
前驱后继
BST典中典了属于是
findnth(findrnk(x)-1)//前驱
findnth(findrnk(x+1))//后继
完整代码
当然是普通平衡树啦
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
const int N=1e6+100;
const int M=2e6+100;
ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,s,t;
struct node{int ls,rs,val,siz,key;
}tr[N<<2];
int r,tot;
il int New(int v){++tot;tr[tot].siz=1;tr[tot].ls=tr[tot].rs=0;tr[tot].key=rand();tr[tot].val=v;return tot;
}
il void pushup(int x){tr[x].siz=tr[tr[x].ls].siz+tr[tr[x].rs].siz+1;return;
}
il int merge(int u,int v){if(!u) return v;if(!v) return u;if(tr[u].key>tr[v].key){tr[u].rs=merge(tr[u].rs,v);pushup(u);return u;}else{tr[v].ls=merge(u,tr[v].ls);pushup(v);return v;}
}
il void split(int x,int v,int &L,int &R){if(!x){L=R=0;return;}if(tr[x].val<=v){L=x;split(tr[L].rs,v,tr[L].rs,R);pushup(L);}else{R=x;split(tr[R].ls,v,L,tr[R].ls);pushup(R);}return;
}
il int findnth(int kth){//printf("findnth:%d\n",kth);int x=r;while(1){//printf("x=%d val=%d siz=%d ls=%d rs=%d\n",x,tr[x].val,tr[x].siz,tr[x].ls,tr[x].rs);if(kth<=tr[tr[x].ls].siz) x=tr[x].ls;else if(kth==tr[tr[x].ls].siz+1) return tr[x].val;else{kth-=tr[tr[x].ls].siz+1;x=tr[x].rs;}}
}
il int findrnk(int v){int a(0),b(0),c(0),res;split(r,v-1,a,b);res=tr[a].siz;r=merge(a,b);return res+1;
}
il void ins(int v){int a(0),b(0),c(0);split(r,v,a,b);c=New(v);r=merge(merge(a,c),b);return;
}
il void del(int v){int a(0),b(0),c(0);split(r,v,a,b);split(a,v-1,a,c);r=merge(merge(a,merge(tr[c].ls,tr[c].rs)),b);
}
int main(){n=read();for(int i=1;i<=n;i++){int op=read(),x=read();switch(op){case 1:{ins(x);break;}case 2:{del(x);break;}case 3:{printf("%d\n",findrnk(x));break;}case 4:{printf("%d\n",findnth(x));break;}case 5:{printf("%d\n",findnth(findrnk(x)-1));break;}case 6:{printf("%d\n",findnth(findrnk(x+1)));break;}}}return 0;
}
/*
*/
thanks for reading!
模板:无旋treap相关推荐
- 无旋treap的简单思想以及模板
因为学了treap,不想弃坑去学splay,终于理解了无旋treap... 好像普通treap没卵用...(再次大雾) 简单说一下思想免得以后忘记.普通treap因为带旋转操作似乎没卵用,而无旋tre ...
- 浅尝无旋Treap (基于洛谷P3391 文艺平衡树)
说是浅尝吧,确实也挺浅的,完全是基于下面这道题写的↓ 洛谷P3391 自己去看题,我是懒得粘了... 分析 其实也没有什么好分析的,这就是一道Splay树的模板题,解决一般的Treap不能解决的区间维 ...
- luogu P2596 [ZJOI2006]书架(平衡树、无旋treap(按排名分裂)一些更复杂的操作)
P2596 [ZJOI2006]书架 无旋treap可以维护一棵树的中序遍历结果.但是不支持通过编号来找节点.于是在无旋treap的基础上,我维护了每个节点的父亲,这样就可以求出一个节点是中序遍历中的 ...
- BST、AVL、BTree、B+Tree、B*Tree、23Tree、234Tree、TTree、RBTree、LLRBTree、AATree、SplayTree、Treap、无旋Treap、scap
喜欢这篇文章吗?喜欢的话去看博主的置顶博客,即可依据分类找到此文章的原版得到更好的体验, 图片及代码显示的问题,笔者深感抱歉,想要更好的体验去原博文即可. title: tree mathjax: t ...
- 无旋treap 文艺平衡树
因为需要用到区间修改,所以该用splay(尚未填坑)或者无旋treap(刚刚填上) 最开始的建树用到了建笛卡尔树的方法,把id大于当前点的点不断出栈,又因为这道题的点是按序入栈的,所以当它无法让更多点 ...
- 无旋Treap(fhq)
一.Treap的性质 Treap就是集BST.Heap二者的性质于一身,即能够支持BST的操作,有能够保证Heap的深度.但BST和Heap的性质似乎有些矛盾,前者是左子树<根<右子树,后 ...
- [BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员 ...
- luogu P3850 [TJOI2007]书架(平衡树、无旋treap(按排名分裂))
luogu P3850 [TJOI2007]书架 这里要的是字符串,所以我们最好用一个map映射一下,不要在结构体中用string代替val. fhq-treap中所有的排名实际上都指的是前面有多少个 ...
- P2596 [ZJOI2006]书架 无旋treap 按照排名分裂
传送门 文章目录 题意: 思路: 题意: 实现如下操作: 思路: fhq-treap板子辣,不要被他的编号误导了,我们还是需要按照排名来分裂,从上到下标号1−n1-n1−n即可,注意在按照排名分裂的时 ...
最新文章
- 《深入理解计算机系统》学习心得二:关于show-bytes的 学习
- Unix的标准I/O与重定向的若干概念解析
- BigData预处理(完整步骤)
- python3反转列表的三种方式
- extend 对象继承
- STM32那点事(5)_ADC(中)
- Docker和Kubernetes应用程序打包:Metaparticle、Pulumi与Ballerina比较
- 智慧农业、数字农业、农产品交易、发布供应、采购详情、报价列表、交易订单、供应大厅、采购大厅、发布采购、采购需求、采购订单、在售商品、出售订单、账户中心、洽谈列表、入驻申请、Axure原型、农业数据看板
- Python中循环(列表循环)的学习笔记~
- ibm服务器安装ghostxp系统,IBM ThinkPad X61s安装WIN XP系统
- 破解大众点评字体反爬
- 面对众多客户/用户需求,每个都紧急,怎么排期?
- 优盘在计算机上无法显示,U盘在电脑上不显示的原因
- spyder python调试_Spyder如何调试
- 人人都是产品经理(善用用户反馈——浅谈用户反馈数据的处理)
- 不要随便借出你的帐号
- SVG动画和CSS转换:复杂的爱情故事
- 作为一个新人,怎样学习嵌入式Linux ?(韦东山)
- Spring使用WebSocket、SockJS、STOMP实现消息功能
- 关于三星SSD的固态优化
热门文章
- redis 查询缓存_Redis缓存总结:淘汰机制、缓存雪崩、数据不一致....
- python基金会主席入门教程_Python基金会-文件IO操作,python,基础
- 输出毫秒_自学单片机第十三篇上:单点输出
- android vcard解析代码,Android使用vcard文件的方法简单实例
- mysql 卸载插件_MySQL 插件安装或卸载(window validate_password 为例)
- 加个ing是什么意思_take的意思竟然是“要求”?奇奇怪怪的熟词僻义打卡终于来了!...
- gather torch_浅谈Pytorch中的torch.gather函数的含义
- python新闻评论分析_从新闻文章中提取评论
- linux gcc出错,编译arm-linux-gcc出错
- 高度平衡的二叉搜索树基础概念与经典题目(Leetcode题解-Python语言)