可并堆
想学非旋转的Treap 然后看到里面提到斜堆 顺便学了学可并堆
可并堆
1.左偏树
其实他介绍了4种可并堆= =
http://hplonline20090711.blog.163.com/blog/static/121969114200961174556682/
2.斜堆
好像说是类似平衡树里的 Splay
merge(a,b) //a.val>b.val 大根堆
merge(a.r,b)
swap(a.l,a.r)
细节什么的还有一点= =
大体思想是合并a和b时 先合并a的右儿子和b 这个新堆是a的新右二子 然后交换a的左右儿子
就像Splay一样不明觉厉 均摊复杂度O(logn)
可并堆的操作 和基础的堆的操作貌似一毛钱关系都没有了呢= =
这是一个斜堆
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=100005; struct Node{ int ls,rs,val; void clear() {ls=rs=0;} }h[N]; int fa[N]; int n,m; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} int merge(int x,int y){ if(x==0) return y; if(y==0) return x; if(h[x].val<h[y].val) swap(x,y); fa[find(y)]=find(x); h[x].rs=merge(h[x].rs,y); swap(h[x].ls,h[x].rs); return x; } int main(){ // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) {scanf("%d",&h[i].val);fa[i]=i;} scanf("%d",&m); for(int i=1;i<=m;i++){ int x,y; if(i==13){ i++;i--; } scanf("%d%d",&x,&y); x=find(x);y=find(y); //printf("%d %d\n",x,y); if(x==y) {printf("-1\n");continue;} h[x].val/=2;h[y].val/=2; int rootx,rooty,root; rootx=merge(h[x].ls,h[x].rs);fa[rootx]=rootx; h[x].clear();fa[x]=x; rootx=merge(rootx,x);fa[rootx]=rootx; rooty=merge(h[y].ls,h[y].rs);fa[rooty]=rooty; h[y].clear();fa[y]=y; rooty=merge(rooty,y);fa[rooty]=rooty; root=merge(rootx,rooty);fa[root]=root; printf("%d\n",h[root].val); //for(int j=1;j<=5;j++) printf("%d %d %d\n",j,h[j].ls,h[j].rs); } }