1. 程式人生 > >並不對勁的斜堆

並不對勁的斜堆

typedef struct nbsp 理解 none href 元素 div htm

為了反駁隔壁很對勁的太刀流,並不對勁的片手流將與之針鋒相對。

很對勁的斜堆、左偏樹簡明教程

它們是可並堆的兩種實現方式。

(假裝二叉堆只包括小根堆。)

二叉堆該如何合並?先想一種暴力的。

現在有根的鍵值較小的二叉堆A,鍵值較大的二叉堆B。

在合並後,A的根肯定還是根。若A的左、右子樹都不為空的話,則可以隨便選一個,再將這個堆與B合並。

遞歸地重復這個過程,直到左、右子樹中有一方為空,直接接過去就行了。

然而這樣時間復雜度並不會得到保障,因為每次“隨便選”的那一個可能更深。這樣時間復雜度就玄學了。

斜堆則是在暴力的基礎上有一些修改。每次必選右(或左)子樹合並,然後交換左右子樹。這樣下次就輪到這次沒能合並的子樹與之合並了。

這聽上去和暴力區別不大,還有那麽一些些的扯。但是類似於splay,它的時間復雜度均攤卻是O(n)的。至於證明,類似於splay,並不對勁的人並不知道,就感性理解吧。

加點操作相當於與一個只有一個節點的斜堆合並。

刪除相當於去掉堆頂元素,再將它的左、右子樹合並。

可以去洛谷p3377測評,但是斜堆不是MLE就是TLE。

技術分享圖片
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include
<algorithm> #define maxn 100010 using namespace std; int read() { int f=1,x=0;char ch=getchar(); while(isdigit(ch)==0 && ch!=-)ch=getchar(); if(ch==-)f=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-0,ch=getchar(); return x*f; } void write(int x) { int ff=0;char ch[15
]; if(x<0) { x=-x; putchar(-); } while(x)ch[++ff]=(x%10)+0,x/=10; if(ff==0)putchar(0); while(ff)putchar(ch[ff--]); putchar(\n); } typedef struct node { int key,ls,rs,siz; }heapnode; struct InterestingHeap { heapnode xx[maxn]; int rt[maxn],fa[maxn],n,q; int x,y,root,son,l,r,tx,ty; bool vis[maxn]; /* void printrt() { cout<<"rt:"<<endl; for(int i=1;i<=n;i++) cout<<rt[i]<<" "; cout<<endl; } void printfa() { cout<<"fa:"<<endl; for(int i=1;i<=n;i++) cout<<fa[i]<<" "; cout<<endl; }*/ bool cmp(int _1,int _2)//Smaller. { return xx[_1].key==xx[_2].key?_1<_2:xx[_1].key<xx[_2].key; } int f(int x){return fa[x]<0?x:fa[x]=f(fa[x]);} void add(int x,int y)//The father is Tx. { tx=f(x),ty=f(y); if(tx==ty)return; fa[ty]=tx; } int merge(int A,int B) { if(!xx[A].siz)return B; if(!xx[B].siz)return A; if(!cmp(A,B))swap(A,B); xx[A].rs=merge(xx[A].rs,B); swap(xx[A].ls,xx[A].rs); xx[A].siz=xx[xx[A].ls].siz+xx[xx[A].rs].siz; return A; } void getit() { x=read(),y=read(); if(vis[x] || vis[y])return; tx=f(x),ty=f(y); if(tx==ty)return; if(!cmp(tx,ty))swap(tx,ty); merge(tx,ty); add(tx,ty); } void delmin(int u) { l=xx[u].ls,r=xx[u].rs; //cout<<u<<" "<<l<<"-"<<r<<endl; if(l==0 && r==0)return; if(l==0 || r==0) { son=l==0?r:l; fa[son]=fa[u],fa[u]=son; rt[-fa[u]]=son; return; } if(!cmp(l,r))swap(l,r); fa[l]=fa[u],fa[r]=l;fa[u]=l; rt[-fa[u]]=l; merge(l,r); } void ask() { // printfa(); x=read(); if(vis[x]){write(-1);return;} root=rt[-fa[f(x)]]; vis[root]=1; write(xx[root].key); delmin(root); // printfa(); } void work() { memset(vis,0,sizeof(vis)); n=read(),q=read(); for(int i=1;i<=n;i++) { xx[i].key=read(); xx[i].siz=1; rt[i]=i; fa[i]=-i; } int f; while(q--) { f=read(); if(f==1) getit(); else ask(); } } }t; int main() { t.work(); return 0; } /* 5 5 1 5 4 2 3 1 1 5 1 2 5 2 2 1 4 2 2 2 */
並不對勁的斜堆

並不對勁的斜堆