【原题题面】传送门
【题解大意】
平衡树模板题。
左旋右旋使数尽量满足左右子树相当的情况。
随机化权值是因为在随机数据下BST趋近于平衡。
同时要维护子树大小和样本容量来回答询问。
具体实现看代码。
【code】
#include<bits/stdc++.h> using namespace std; #define File1 "input" #define File2 "output" #define inf 0x7fffffff #define ll long long inline void file(){ freopen(File1".in","r",stdin); freopen(File2".out","w",stdout); } inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x*f; } const int mxn = 1e5+5; int n; struct node{ int l,r,v,sz,cnt,dat; }t[mxn]; int tot;//the number of point inline int New(int v){ t[++tot].v = v; t[tot].dat = rand(); t[tot].cnt = t[tot].sz = 1;//new ! return tot; } inline void Update(int p){ t[p].sz = t[t[p].l].sz + t[t[p].r].sz + t[p].cnt; } int rt; inline void Build(){ New(-inf),New(inf); t[rt=1].r = 2; Update(rt); } inline void zig(int &y){ int x = t[y].l; t[y].l = t[x].r; t[x].r = y; y = x;//y为引用,跟进行了修改,所以更改根 Update(t[y].r),Update(y);//其实改的是此时的根 } inline void zag(int &x){ int y = t[x].r; t[x].r = t[y].l; t[y].l = x; x = y;//同理 Update(t[x].l),Update(x); } inline void Insert(int &x,int v){ if(x == 0){ x = New(v); return; }//p借用rt值 if(v == t[x].v){ t[x].cnt ++; Update(x); return; } if(v < t[x].v){ Insert(t[x].l,v); if(t[x].dat < t[t[x].l].dat) zig(x); }//left else{ Insert(t[x].r,v); if(t[x].dat < t[t[x].r].dat) zag(x); } Update(x); return; } inline void Remove(int &x,int v){ if(x == 0) return; if(v == t[x].v){ if(t[x].cnt > 1){ t[x].cnt--; Update(x); return; }else{ if(t[x].l || t[x].r){ if(t[x].r == 0 || t[t[x].l].dat > t[t[x].r].dat) zig(x),Remove(t[x].r,v); else zag(x),Remove(t[x].l,v); Update(x); } else x = 0; return; } } v < t[x].v ? Remove(t[x].l,v):Remove(t[x].r,v); Update(x); } inline int Get_rk_By_v(int x,int v){ if(x == 0) return 0; if(v == t[x].v) return t[t[x].l].sz + 1; if(v < t[x].v) return Get_rk_By_v(t[x].l,v); return Get_rk_By_v(t[x].r,v) + t[t[x].l].sz + t[x].cnt; } inline int Get_v_By_rk(int x,int rk){ if(x == 0) return inf; if(t[t[x].l].sz >= rk) return Get_v_By_rk(t[x].l,rk); if(t[t[x].l].sz + t[x].cnt >= rk) return t[x].v; return Get_v_By_rk(t[x].r,rk-t[t[x].l].sz-t[x].cnt); } inline int Getpre(int v){ int ans(1); int x = rt; while(x){ if(v == t[x].v){ if(t[x].l > 0){ x = t[x].l; while(t[x].r > 0) x = t[x].r; ans = x; } break; } if(t[x].v < v && t[x].v > t[ans].v) ans = x; x = v < t[x].v ? t[x].l : t[x].r; } return t[ans].v; } inline int Getnxt(int v){ int ans = 2; int x = rt; while(x){ if(v == t[x].v){ if(t[x].r > 0){ x = t[x].r; while(t[x].l > 0) x = t[x].l; ans = x; } break; } if(t[x].v > v && t[x].v < t[ans].v) ans = x; x = v < t[x].v ? t[x].l : t[x].r; } return t[ans].v; } int main(){ // file(); Build(); n = read(); for(int i = 1;i <= n; ++i){ int opt = read(),x = read(); switch(opt){ case 1: Insert(rt,x); break; case 2: Remove(rt,x); break; case 3: printf("%d ",Get_rk_By_v(rt,x)-1); break; case 4: printf("%d ",Get_v_By_rk(rt,x+1)); break; case 5: printf("%d ",Getpre(x)); break; case 6: printf("%d ",Getnxt(x)); break; } } return 0; } /* 8 1 10 1 20 1 30 3 20 4 2 2 10 5 25 6 -1 */