平衡树模板
Treap
通过维护堆的性质,使平衡树平衡,操作是旋转。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+2022,inf=0x3f3f3f3f;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
struct node{
int l,r,val,num,size,rnd;
}e[N];
int t,opt,vv,cnt,root;
void newnode(int val){
cnt++;
e[cnt].rnd=rand()*32767+rand();
e[cnt].num=e[cnt].size=1;
e[cnt].val=val;
return;
}
void pushup(int u){
e[u].size=e[e[u].l].size+e[e[u].r].size+e[u].num;
return;
}
void zag(int &u){
int x=e[u].r;
e[u].r=e[x].l;
e[x].l=u;
u=x;
pushup(e[u].l),pushup(u);
return;
}
void zig(int &u){
int x=e[u].l;
e[u].l=e[x].r;
e[x].r=u;
u=x;
pushup(e[u].r),pushup(u);
return;
}
void insert(int &u,int key){
if(!u){
newnode(key),u=cnt;
return;
}
if(e[u].val==key)e[u].num++;
if(key<e[u].val){
insert(e[u].l,key);
if(e[u].rnd<e[e[u].l].rnd)zig(u);
}
if(key>e[u].val){
insert(e[u].r,key);
if(e[u].rnd<e[e[u].r].rnd)zag(u);
}
pushup(u);
return;
}
void erase(int &u,int key){
if(!u)return;
if(e[u].val==key){
if(e[u].num>1)e[u].num--;
else{
if(!e[u].l)u=e[u].r;
else if(!e[u].r)u=e[u].l;
else if(e[e[u].l].rnd>e[e[u].r].rnd){
zig(u);
erase(e[u].r,key);
}
else{
zag(u);
erase(e[u].l,key);
}
}
}
else if(key<e[u].val)erase(e[u].l,key);
else if(key>e[u].val)erase(e[u].r,key);
pushup(u);
return;
}
int get_rank(int u,int key){
if(!u)return 0;
if(e[u].val==key)return e[e[u].l].size;
if(key<e[u].val)return get_rank(e[u].l,key);
if(key>e[u].val)return e[e[u].l].size+e[u].num+get_rank(e[u].r,key);
}
int get_val(int u,int key){
if(!u)return 0;
if(e[e[u].l].size>=key)return get_val(e[u].l,key);
if(e[e[u].l].size+e[u].num>=key)return e[u].val;
return get_val(e[u].r,key-e[u].num-e[e[u].l].size);
}
int get_pre(int u,int key){
if(!u)return -inf;
if(key<=e[u].val)return get_pre(e[u].l,key);
else return max(e[u].val,get_pre(e[u].r,key));
}
int get_nxt(int u,int key){
if(!u)return inf;
if(key>=e[u].val)return get_nxt(e[u].r,key);
else return min(e[u].val,get_nxt(e[u].l,key));
}
int main(){
srand(time(NULL));
newnode(-inf);
newnode(inf);
e[1].r=2;
e[1].size=2;
root=1;
if(e[1].rnd<e[2].rnd)zag(root);
t=read();
while(t--){
opt=read(),vv=read();
if(opt==1)insert(root,vv);
if(opt==2)erase(root,vv);
if(opt==3)printf("%d\n",get_rank(root,vv));
if(opt==4)printf("%d\n",get_val(root,vv+1));
if(opt==5)printf("%d\n",get_pre(root,vv));
if(opt==6)printf("%d\n",get_nxt(root,vv));
}
return 0;
}
Splay
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+2022;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
struct node{
int ch[2],v,lazy,size,fa;
}tr[N];
int n,m,root,tot;
int newnode(int p,int v){
tr[++tot].v=v;
tr[tot].fa=p;
tr[tot].size=1;
return tot;
}
void pushup(int u){
tr[u].size=1+tr[tr[u].ch[0]].size+tr[tr[u].ch[1]].size;
return;
}
void rotate(int x){
int y=tr[x].fa,z=tr[y].fa;
int k=(tr[y].ch[1]==x);
tr[z].ch[tr[z].ch[1]==y]=x,tr[x].fa=z;
tr[y].ch[k]=tr[x].ch[k^1],tr[tr[x].ch[k^1]].fa=y;
tr[x].ch[k^1]=z,tr[z].fa=x;
pushup(y),pushup(x);
return;
}
void pushdown(int u){
if(tr[u].lazy){
swap(tr[u].ch[0],tr[u].ch[1]);
tr[u].lazy=0;
tr[tr[u].ch[0]].lazy^=1;
tr[tr[u].ch[1]].lazy^=1;
}
return;
}
void print(int u){
pushdown(u);
if(tr[u].ch[0])print(tr[u].ch[0]);
if(tr[u].v!=0 && tr[u].v!=n+1)printf("%d ",tr[u].v);
if(tr[u].ch[0])print(tr[u].ch[1]);
return;
}
void splay(int x,int k){
while(tr[x].fa!=k){
int y=tr[x].fa,z=tr[y].fa;
if(z!=k){
if((tr[y].ch[1]==x)!=(tr[z].ch[1]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
if(!k)root=x;
return;
}
int get_k(int k){
int u=root;
while(1){
pushdown(u);
if(tr[tr[u].ch[0]].size>=k)u=tr[u].ch[0];
else if(tr[tr[u].ch[0]].size+1==k)return u;
else k-=tr[tr[u].ch[0]].size+1,u=tr[u].ch[1];
}
}
void insert(int p,int v){
if(!tr[p].ch[v>tr[p].v])tr[p].ch[v>tr[p].v]=newnode(p,v);
else insert(tr[p].ch[v>tr[p].v],v);
return;
}
void ts(int u){
cout<<u<<" "<<tr[u].ch[0]<<" "<<tr[u].ch[1]<<endl;
if(tr[u].ch[0])ts(tr[u].ch[0]);
if(tr[u].ch[1])ts(tr[u].ch[1]);
return;
}
int main(){
n=read(),m=read();
for(int i=0;i<n+2;i++){
insert(root,i);
splay(tot,0);
ts(root);
cout<<endl;
}
while(m--){
int L,R,l,r;
l=read(),r=read();
L=get_k(l),R=get_k(r+2);
splay(L,0),splay(R,L);
tr[tr[R].ch[0]].lazy^=1;
}
print(root);
return 0;
}
FHQ Treap
学会分裂合并,你将不用旋转。
合并的时候注意顺序,merge(A,B)
是合并成A在B的前面。
还有注意pushup
的位置,别把0号点pushup
了。
事实上他很适合处理区间问题,因为他的中序遍历就是原序列(废话),要处理一个区间只需要暴力split
这个区间即可。
l=read(),r=read();
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
e[y].lazy^=1;//这是区间上的操作
rt=merge(merge(x,y),z);
CODE
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+110;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
int n,opt,x,y,cnt,rt,z;
struct node{
int val,rad,size;
}e[N];
int ls[N],rs[N];
void pushup(int u){e[u].size=e[ls[u]].size+e[rs[u]].size+1;return;}
void split(int u,int val,int &x,int &y){
if(!u)x=y=0;
else{
if(e[u].val<=val)x=u,split(rs[u],val,rs[u],y);
else y=u,split(ls[u],val,x,ls[u]);
pushup(u);
}
return;
}
//split也可以按排名分裂
/*
void split(int u,int k,int &x,int &y){
if(!u)x=0,y=0;
else{
if(k>e[ls[u]].size){x=u,split(rs[u],k-e[ls[u]].size-1,rs[u],y);}
else{y=u,split(ls[u],k,x,ls[y]);}
pushup(u);
}
return;
}
*/
int merge(int A,int B){
if(!A || !B)return A+B;
if(e[A].rad<e[B].rad){rs[A]=merge(rs[A],B);pushup(A);return A;}
else {ls[B]=merge(A,ls[B]);pushup(B);return B;}
}
int newnode(int val){
e[++cnt].rad=rand()*32767+rand();
e[cnt].val=val;
e[cnt].size=1;
return cnt;
}
void insert(int val){
split(rt,val,x,y);
rt=merge(merge(x,newnode(val)),y);
return;
}
void erase(int val){
split(rt,val,x,z);
split(x,val-1,x,y);
y=merge(ls[y],rs[y]);
rt=merge(merge(x,y),z);
return;
}
int get_rank(int val){
split(rt,val-1,x,y);
int tmp=e[x].size+1;
rt=merge(x,y);
return tmp;
}
int kth(int u,int k){
if(!u)return 0;
if(k<=e[ls[u]].size)return kth(ls[u],k);
if(k<=e[ls[u]].size+1)return u;
return kth(rs[u],k-1-e[ls[u]].size);
}
int pre(int val){
split(rt,val-1,x,y);
int tmp=kth(x,e[x].size);
rt=merge(x,y);
return e[tmp].val;
}
int nxt(int val){
split(rt,val,x,y);
int tmp=kth(y,1);
rt=merge(x,y);
return e[tmp].val;
}
int main(){
srand('F'+'H'+'Q'+'Y'+'Y'+'D'+'S');
n=read();
for(int i=1;i<=n;i++){
opt=read();
if(opt==1)insert(read());
if(opt==2)erase(read());
if(opt==3)printf("%d\n",get_rank(read()));
if(opt==4)printf("%d\n",e[kth(rt,read())].val);
if(opt==5)printf("%d\n",pre(read()));
if(opt==6)printf("%d\n",nxt(read()));
}
return 0;
}
文艺平衡树
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+110;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
int rt,cnt,x,y,z,ls[N],rs[N];
struct node{
int val,rad,size,lazy;
}e[N];
int n,m;
void pushup(int u){e[u].size=1+e[ls[u]].size+e[rs[u]].size;return;}
int newnode(){e[++cnt].rad=rand(); e[cnt].size=1;return cnt;}
void pushdown(int u){
if(e[u].lazy){
swap(ls[u],rs[u]);e[ls[u]].lazy^=1,e[rs[u]].lazy^=1;
e[u].lazy=0;
}
return;
}
void split(int u,int k,int &x,int &y){
if(!u)x=0,y=0;
pushdown(u);//pushdown标记
else{
if(k>e[ls[u]].size){pushdown(x);x=u,split(rs[u],k-e[ls[u]].size-1,rs[u],y);}
else{pushdown(y);y=u,split(ls[u],k,x,ls[y]);}
pushup(u);
}
return;
}
int merge(int A,int B){
if(!A || !B)return A+B;
if(e[A].rad<e[B].rad){pushdown(A);rs[A]=merge(rs[A],B);pushup(A);return A;}
else{pushdown(B);ls[B]=merge(A,ls[B]);pushup(B);return B;}
//别忘记pushdown
}
void insert(int k){
split(rt,k,x,y);
rt=merge(merge(x,newnode()),y);
return;
}
void print(int u){
if(!u)return;
pushdown(u);
print(ls[u]);
printf("%d ",u);
print(rs[u]);
return;
}
int main(){
srand('F'+'J');int l,r;
n=read(),m=read();
for(int i=1;i<=n;i++)insert(i-1);
for(int i=1;i<=m;i++){
l=read(),r=read();
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
e[y].lazy^=1;
rt=merge(merge(x,y),z);
}
print(rt);
return 0;
}
可持久化文艺平衡树
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=4e5*50;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
struct node{
int val,rad,size,lazy;ll sum;
}e[N];
int ls[N],rs[N],rt[N],cnt,x,y,z;
int dust[N],bin;//垃圾回收:删掉的点重新用
int newnode(int val){
int xv=bin?dust[bin--]:++cnt;
e[xv].rad=rand();
e[xv].val=val;
e[xv].sum=val;
e[xv].size=1;
ls[xv]=0;
rs[xv]=0;
return xv;
}
int clone(int u){
int xv=bin?dust[bin--]:++cnt;
e[xv].rad=e[u].rad;//不复制会MLE?WHY?
e[xv].val=e[u].val;
e[xv].sum=e[u].sum;
e[xv].size=e[u].size;
e[xv].lazy=e[u].lazy;//lazy没复制卡了我5h
ls[xv]=ls[u];
rs[xv]=rs[u];
return xv;
}
void pushdown(int u){
if(e[u].lazy){
swap(ls[u],rs[u]);
if(ls[u]){ls[u]=clone(ls[u]);e[ls[u]].lazy^=1;}
if(rs[u]){rs[u]=clone(rs[u]);e[rs[u]].lazy^=1;}
e[u].lazy=0;
}
return;
}
void pushup(int u){
e[u].size=1+e[ls[u]].size+e[rs[u]].size;
e[u].sum=(ll)e[u].val+e[ls[u]].sum+e[rs[u]].sum;
return;
}
void split(int u,int k,int &x,int &y){
if(!u)x=y=0;
else{
pushdown(u);
if(k>e[ls[u]].size){
x=clone(u);//不一样的地方
split(rs[x],k-1-e[ls[u]].size,rs[x],y);
pushup(x);
}
else{
y=clone(u);
split(ls[y],k,x,ls[y]);
pushup(y);
}
}
return;
}
int merge(int A,int B){
if(!A || !B)return A+B;
else{
if(e[A].rad<e[B].rad){
pushdown(A);
rs[A]=merge(rs[A],B);
pushup(A);
return A;
}
else{
pushdown(B);
ls[B]=merge(A,ls[B]);
pushup(B);
return B;
}
}
}
void insert(int &u,int k,int val){
split(u,k,x,y);
u=merge(merge(x,newnode(val)),y);
return;
}
void erase(int &u,int k){
split(u,k-1,x,y);
split(y,1,y,z);
dust[++bin]=y;
u=merge(x,z);
return;
}
void revise(int &u,int l,int r){//别忘记u要传值
split(u,l-1,x,y);
split(y,r-l+1,y,z);
e[y].lazy^=1;
u=merge(merge(x,y),z);
return;
}
ll query(int &u,int l,int r){
split(u,l-1,x,y);
split(y,r-l+1,y,z);
ll res=e[y].sum;
u=merge(merge(x,y),z);
return res;
}
int n,l,r,v,opt;ll lastans;
int main(){
srand(114514);n=read();//垃圾种子
for(int i=1;i<=n;i++){
v=read();opt=read();
rt[i]=rt[v];
if(opt==1){
l=read(),r=read();
l^=lastans,r^=lastans;
insert(rt[i],l,r);
}
if(opt==2){
l=read();l^=lastans;
erase(rt[i],l);
}
if(opt==3){
l=read(),r=read();
l^=lastans,r^=lastans;
if(l>r)swap(l,r);//额。。。
revise(rt[i],l,r);
}
if(opt==4){
l=read(),r=read();
l^=lastans,r^=lastans;
if(l>r)swap(l,r);
lastans=query(rt[i],l,r);
printf("%lld\n",lastans);//long long
}
}
return 0;
}
可持久化平衡树
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5*50;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
struct node{
int val,rad,size;
}e[N];
int ls[N],rs[N],rt[N],cnt,x,y,z,n;
int newnode(int val){
int xv=++cnt;
e[xv].rad=rand(),e[xv].val=val,e[xv].size=1;ls[xv]=0,rs[xv]=0;
return xv;
}
void pushup(int u){e[u].size=1+e[ls[u]].size+e[rs[u]].size;return;}
int clone(int u){
int xv=++cnt;
e[xv]=e[u];ls[xv]=ls[u];rs[xv]=rs[u];
return xv;
}
void split(int u,int val,int &x,int &y){
if(!u)x=y=0;
else{
if(e[u].val<=val){x=clone(u);split(rs[x],val,rs[x],y);pushup(x);}
else{y=clone(u);split(ls[y],val,x,ls[y]);pushup(y);}
}
return;
}
int merge(int A,int B){
if(!A || !B)return A+B;
else{
if(e[A].rad<e[B].rad){
int tmp=clone(A);
rs[tmp]=merge(rs[tmp],B);
pushup(tmp);
return tmp;
}
else{
int tmp=clone(B);
ls[tmp]=merge(A,ls[tmp]);
pushup(tmp);
return tmp;
}
}
}
void insert(int &u,int val){
split(u,val,x,y);
u=merge(merge(x,newnode(val)),y);
return;
}
void erase(int &u,int val){
split(u,val,x,z);
split(x,val-1,x,y);
y=merge(ls[y],rs[y]);
u=merge(merge(x,y),z);
return;
}
int get_rank(int u,int val){
if(!u)return 0;
if(val<e[u].val)return get_rank(ls[u],val);
if(val==e[u].val)return e[ls[u]].size+get_rank(rs[u],val);
if(val>e[u].val)return 1+e[ls[u]].size+get_rank(rs[u],val);
}
int kth(int u,int k){
if(!u)return 0;
if(k<=e[ls[u]].size)return kth(ls[u],k);
if(k<=e[ls[u]].size+1)return u;
return kth(rs[u],k-1-e[ls[u]].size);
}
int pre(int &u,int val){
split(u,val-1,x,y);
int tmp=kth(x,e[x].size);
u=merge(x,y);
return e[tmp].val;
}
int nxt(int &u,int val){
split(u,val,x,y);
int tmp=kth(y,1);
u=merge(x,y);
return e[tmp].val;
}
signed main(){
int seed='L'+'J'+'P'+'i'+'n'+'g'+'H'+'e'+'n'+'g'+'S'+'h'+'u'+'H'+'u'+'i'+'W'+'o'+'Q'+'i'+'n'+'g'+'C'+'h'+'u'+'n';srand(seed);
n=read();int v,opt,val,k;
insert(rt[0],-2147483647);insert(rt[0],2147483647);
for(int i=1;i<=n;i++){
v=read(),opt=read();rt[i]=rt[v];
if(opt==1){val=read();insert(rt[i],val);}
if(opt==2){val=read();erase(rt[i],val);}
if(opt==3){val=read();printf("%d\n",get_rank(rt[i],val))-1;}
if(opt==4){k=read();printf("%d\n",e[kth(rt[i],k+1)].val);}
if(opt==5){val=read();printf("%d\n",pre(rt[i],val));}
if(opt==6){val=read();printf("%d\n",nxt(rt[i],val));}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】