FHQ Treap
2022年10月3日
这波我吹爆 fhq treap,代码简短功能强大不易写错。
据说常数大一点?我不知道啊,反正能写出来就是胜利(?)。
SP4487 GSS6 - Can you answer these queries VI
点击查看代码
/* * Author: ShaoJia * Last Modified time: 2022-10-03 21:28:32 * Motto: We'll be counting stars. */ #pragma GCC optimize("Ofast") #include<bits/stdc++.h> using namespace std; #define debug(...) cerr<<"#"<<__LINE__<<": "<<__VA_ARGS__<<endl #define For(i,j,k) for(int i=(j),i##_=(k);i<=i##_;i++) #define Rof(i,j,k) for(int i=(j),i##_=(k);i>=i##_;i--) #define lob lower_bound #define upb upper_bound #define fir first #define sec second #define mkp make_pair #define siz(x) ((int)(x).size()) #define pb emplace_back #define ckmx(a,b) a=max(a,b) #define ckmn(a,b) a=min(a,b) #define ll long long #define pi pair<int,int> #define N 200010 mt19937 rgen(time(0)+size_t(new(char))); struct node{ int sz,l,r,sum,ans; node(){} node(int x){ sz=1,l=r=sum=ans=x; } node(int x,int y,int z,int w,int aa){ sz=x,l=y,r=z,sum=w,ans=aa; } friend node operator+(const node& x,const node& y){ return node(x.sz+y.sz, max(x.l,x.sum+y.l), max(y.r,y.sum+x.r), x.sum+y.sum, max({x.ans,y.ans,x.r+y.l}) ); } }t[N]; int ls[N],rs[N],w[N],v[N],root=0,tot=0; void upd(int rt){ t[rt]=node(v[rt]); if(ls[rt]) t[rt]=t[ls[rt]]+t[rt]; if(rs[rt]) t[rt]=t[rt]+t[rs[rt]]; } int nnd(int val){ t[++tot]=node(val); v[tot]=val; ls[tot]=rs[tot]=0; w[tot]=rgen(); return tot; } int merge(int x,int y){ // cout<<x<<"~"<<y<<"\n"; if(!x || !y) return x^y; if(w[x]>w[y]){ rs[x]=merge(rs[x],y); upd(x); return x; }else{ ls[y]=merge(x,ls[y]); upd(y); return y; } } void split(int rt,int k,int &l,int &r){ if(!rt) return l=r=0,void(); if(k<=t[ls[rt]].sz) r=rt,split(ls[rt],k,l,ls[rt]); else l=rt,split(rs[rt],k-t[ls[rt]].sz-1,rs[rt],r); upd(rt); } void print(int rt){ if(!rt) return ; print(ls[rt]); cout<<v[rt]<<" "; print(rs[rt]); } signed main(){ios::sync_with_stdio(false),cin.tie(nullptr); int cnt,x,y,a,b,c,tmp; char opt; cin>>cnt; while(cnt--){ cin>>x; // print(root); cout<<"\n"; root=merge(root,nnd(x)); } cin>>cnt; while(cnt--){ // print(root); // cout<<"\n"; cin>>opt>>x; if(opt=='I'){ cin>>y; split(root,x-1,a,b); root=merge(merge(a,nnd(y)),b); }else if(opt=='D'){ split(root,x,c,b); split(c,x-1,a,tmp); root=merge(a,b); }else if(opt=='R'){ cin>>y; split(root,x,c,b); split(c,x-1,a,tmp); root=merge(a,merge(nnd(y),b)); }else{ cin>>y; split(root,y,tmp,c); split(tmp,x-1,a,b); // print(b); cout<<"----\n"; cout<<t[b].ans<<"\n"; root=merge(a,merge(b,c)); } } return 0;}
远古
本质:无 rotate 平衡树。
一旦没了 rotate,代码就短好多,思路也清晰。
首先说一下,这个东西可以搞一切 bst , treap , splay 所能搞的东西。
——自为风月马前卒
树的基本东西(正常):
struct node{ int sz;//树的大小 int w;//随机数满足大顶堆 int val;//Key_value int ls,rs;//左右儿子 }t[N]; int root=0;//整棵树的根 int tot=0;//类似前向星,存最大下标 void upd(int rt){//更新 sz t[rt].sz=t[t[rt].ls].sz+t[t[rt].rs].sz+1; } int nwnd(int x){//新建节点 t[++tot]={1,rand(),x,0,0}; return tot; }
整个数据结构中只有 种操作、 种询问:
- 把一棵树分成两棵树。
//将 rt 为根的树分成 <=val 和 >val 两部分,两个根节点存入 l 和 r void split(int rt,int val,int &l,int &r){ if(!rt){l=r=0;return ;}//没了!? if(t[rt].val<=val) l=rt,split(t[rt].rs,val,t[rt].rs,r);//右边开裂 else r=rt,split(t[rt].ls,val,l,t[rt].ls);//左边开裂 upd(rt); }
- 把两棵树合成一棵树。
//将根为 x 和 y 的树合并 int merge(int x,int y){ if(!x || !y) return x+y;//一方没了 if(t[x].w>t[y].w) {t[x].rs=merge(t[x].rs,y);upd(x);return x;}//x 为根 else {t[y].ls=merge(x,t[y].ls);upd(y);return y;}//y 为根 }
- 查找一棵树里的第 小(二分查找)。
//查找根为 rt 的树内 val 第 x 小的位置 int kth(int rt,int x){ int rk; while(true){ rk=t[t[rt].ls].sz+1; if(x==rk) return rt; if(x<rk) rt=t[rt].ls; else x-=rk, rt=t[rt].rs; } }
就结束了……
我们看看各项操作是如何通过上述操作实现的:
- 插入 。
split(root,x,a,b); root=merge(merge(a,nwnd(x)),b);
- 删除 (若有多个相同的数,只删除一个)。
split(root,x,a,c); split(a,x-1,a,b); root=merge(merge(a,t[b].ls),merge(t[b].rs,c));
- 查询 的排名(排名定义为比当前数小的数的个数 )。
split(root,x-1,a,b); cout<<t[a].sz+1<<endl; root=merge(a,b);
- 查询排名为 的数。
cout<<t[kth(root,x)].val<<endl;
- 求 的前驱。
split(root,x-1,a,b); cout<<t[kth(a,t[a].sz)].val<<endl; root=merge(a,b);
- 求 的后继。
split(root,x,a,b); cout<<t[kth(b,1)].val<<endl; root=merge(a,b);
最后说一下,FHQ 其实是可以处理区间问题的(像 Splay 一样)。
本文来自博客园,作者:ShaoJia,版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义