题解 P3369

丛雨

2019-12-02 16:11:51

Solution

## 看到没有AVL的题解,来水一波 ### 变量声明 #### $l($左儿子$),r($右儿子$),v($值$),h($高度$),s($子树大小$),si($当前数出现次数$)$ ### 函数声明 1. $ levo($左旋$)$ 示意图: ![](https://cdn.luogu.com.cn/upload/image_hosting/7czt0s9q.png?x-oss-process=image/resize,m_lfit,h_170,w_225) # $\ \ \ \ \ \ \ \ \ \ \ \downarrow$ ![](https://cdn.luogu.com.cn/upload/image_hosting/12wujpcf.png?x-oss-process=image/resize,m_lfit,h_170,w_225) 可见,此操作使得$height(树)$从$max(h(c),h(d)+1,h(e)+1)$变为了$max(h(c)+1,h(d)+1,h(e))$ 2. $ dext($右旋$)$ 显然,只是上面对称了下而已 3. $ lext($左右旋$)$ 先对根节点的左节点做左旋,再在根节点做右旋 示意图: ![](https://cdn.luogu.com.cn/upload/image_hosting/vv3mt4gj.png?x-oss-process=image/resize,m_lfit,h_170,w_225) # $\ \ \ \ \ \ \ \ \ \ \ \downarrow$ ![](https://cdn.luogu.com.cn/upload/image_hosting/2z1gxl1f.png?x-oss-process=image/resize,m_lfit,h_170,w_225) 4. $devo($右左旋$)$ 上图对称了下 5. $balance($平衡$)$ 首先,$AVL$需保证任意节点的左子树与右子树高度差$\leq 1(h(null)=0)$ 假设该树在插入$or$删除前已经为$AVL$,可知,任意节点的左右子树高度差在修改后最大为$2.$ 再假设当前已经使节点$n$的儿子平衡,我们需要使树$n$平衡 - $h(ls(n))=h(rs(n))+2$ - $h(ls(ls(n))) > h(ls(rs(n)))$ 可知,左子树的左儿子最高,所以进行右旋 - $h(ls(ls(n))) < h(ls(rs(n)))$ 可知,左子树的右儿子最高,所以进行左右旋 - $h(ls(n))+2=h(rs(n))$ - $h(rs(rs(n))) > h(rs(ls(n)))$ 可知,右子树的右儿子最高,所以进行左旋 - $h(rs(rs(n))) < h(rs(ls(n)))$ 可知,右子树的左儿子最高,所以进行右左旋 6. $includeremove(now,need)$内置删除操作 - $now=null\ \ \ \ \ \ \ return\ null$ - $v(now)>need\ \ \ $把当前点的左儿子赋为$includeremove(ls(now),need)$ - $v(now)<need\ \ \ $把当前点的右儿子赋为$includeremove(rs(now),need)$ - $v(now)=need\ \ \ $ - $si(now)=1$ - $ls(now) \neq null \And rs(now) \neq null$ 把当前点置为左子树中的最大值对应的节点(右子树中的最小值对应的节点),再**完全、完全、完全**删掉左子树中(右子树中)哪个可怜的被"冒名顶替"节点,$return$当前点 - $ls(now) \neq null \And rs(now) = null$ 把当前点置为他的右儿子~~被儿子ntr了~~ - $rs(now) \neq null \And ls(now) = null$ 把当前点置为他的左儿子~~被儿子ntr了~~ - $si(now) > 1$ 直接$--si(now)$ 7. $lower(n)\And biger(n) \And findrank(n) \And findindex(n) \And findmax(n) \And findmin(n) \And insert $等 太简单了,直接跳过 $\mathfrak{talk\ is\ cheap,show\ you\ the\ code}$ ```cpp #include<cstdio> # define read read1<int>() # define Type template<typename T> Type inline const T read1() { T m=0; char k=getchar(); while(('0'>k||k>'9')&&(k!='-'))k=getchar(); const bool f=(k=='-'?1:0); if(f)k=getchar(); while('0'<=k&&k<='9')m=(m<<3)+(m<<1)+(k^48),k=getchar(); return f?-m:m; } Type const T Max(T a,T b){return a>b?a:b;} Type struct AVL { int tot; struct node { node *l,*r; T v; int h,s,si; node(T tv){l=r=NULL;v=tv;h=s=si=1;} node(){l=r=NULL;v=0;h=s=si=1;} }*Root,f[1000000]; AVL(){Root=NULL;tot=0;} int height(node *now) { return now?now->h:0; } int size(node *now) { return now?now->s:0; } node* includefindindex(node *now,int k) { if(k<=size(now->l))return includefindindex(now->l,k); if(k>size(now->l)+now->si)return includefindindex(now->r,k-(size(now->l)+now->si)); return now; } T operator [](int k) { return includefindindex(Root,k)->v; } node* find(T want) { node *tem=Root; while(tem&&tem->v!=want) if(tem->v>want)tem=tem->l; else tem=tem->r; return tem; } int findrank(T want) { node *tem=Root; int t=0; while(tem) { if(tem->v<want)t+=size(tem->l)+tem->si,tem=tem->r; else if(tem->v>want)tem=tem->l; else return t+size(tem->l)+1; } return 1; } node* levo(node *now) { node *tem=now->r; now->r=tem->l; tem->l=now; now->h=Max(height(now->l),height(now->r))+1; now->s=size(now->l)+size(now->r)+now->si; tem->h=Max(height(tem->l),height(tem->r))+1; tem->s=size(tem->l)+size(tem->r)+tem->si; return tem; } node* dext(node *now) { node *tem=now->l; now->l=tem->r; tem->r=now; now->h=Max(height(now->l),height(now->r))+1; now->s=size(now->l)+size(now->r)+now->si; tem->h=Max(height(tem->l),height(tem->r))+1; tem->s=size(tem->l)+size(tem->r)+tem->si; return tem; } node* lext(node *now) { now->l=levo(now->l); return dext(now); } node* devo(node *now) { now->r=dext(now->r); return levo(now); } node* balance(node *now) { if(height(now->l)==height(now->r)+2) if(height(now->l->l)>height(now->l->r))now=dext(now); else now=lext(now); else if(height(now->r)==height(now->l)+2) if(height(now->r->r)>height(now->r->l))now=levo(now); else now=devo(now); return now; } node* findmin(node *now) { if(!now)return NULL; while(now->l)now=now->l; return now; } node* findmax(node *now) { if(!now)return NULL; while(now->r)now=now->r; return now; } node* includeinsert(node *now,T need) { if(!now) { now=f+(tot++); now->v=need; return now; } if(need==now->v)++now->si; else if(need<now->v)now->l=includeinsert(now->l,need); else now->r=includeinsert(now->r,need); now->h=Max(height(now->l),height(now->r))+1; now->s=size(now->l)+size(now->r)+now->si; return balance(now); } node* includeremove(node *now,T need) { if(!now)return NULL; if(now->v>need)now->l=includeremove(now->l,need); else if(now->v<need)now->r=includeremove(now->r,need); else if(now->si>1)--now->si; else if(now->l&&now->r) { node* tem=findmin(now->r); now->v=tem->v;now->si=tem->si; tem->si=1; now->r=includeremove(now->r,now->v); } else if(now->l||now->r)now=now->l?now->l:now->r; else return now=NULL; now->h=Max(height(now->l),height(now->r))+1; now->s=size(now->l)+size(now->r)+now->si; return balance(now); } node* bigger(T need) { node *tem=Root,*ans=NULL; while(tem) { if(tem->v>need) { if(!ans||tem->v<ans->v)ans=tem; tem=tem->l; } else tem=tem->r; } return ans; } node* lower(T need) { node *tem=Root,*ans=NULL; while(tem) { if(tem->v<need) { if(!ans||tem->v>ans->v)ans=tem; tem=tem->r; } else tem=tem->l; } return ans; } void insert(T need){Root=includeinsert(Root,need);} void remove(T need){Root=includeremove(Root,need);} }; AVL<int>tree; int main() { int s=read; while(s--) switch(read) { case 1:tree.insert(read);break; case 2:tree.remove(read);break; case 3:printf("%d\n",tree.findrank(read));break; case 4:printf("%d\n",tree[read]);break; case 5:printf("%d\n",tree.lower(read)->v);break; default:printf("%d\n",tree.bigger(read)->v); } return 0; } ```