左偏树(可并堆)
可并堆就是一种可以支持合并操作的堆,满足堆的性质,主要就是还要满足左子树比右子树要长,然后就直接进行合并操作的时候,直接连在上一个的右子树就行了。然后每次交换一下两个子树的位置(左右互换)。
直接粘贴板子代码。
#include<cstdio> #include<iostream> using namespace std; int n,m; int V[100100]; int pa[100100]; int dist[100100]; int lc[100010],rc[100010]; int find(int a) { while(pa[a]) a = pa[a]; return a; } int Merge(int x,int y) { if(!x || !y) return x | y; if(V[x] > V[y] || (V[x] == V[y] && x > y)) swap(x,y); rc[x] = Merge(rc[x],y); pa[rc[x]] = x; if(dist[lc[x]] < dist[rc[x]]) swap(lc[x],rc[x]); dist[x] = dist[rc[x]] + 1; return x; } void pop(int x) { V[x] = -1; pa[rc[x]] = pa[lc[x]] = 0; Merge(lc[x],rc[x]); } int main() { scanf("%d%d",&n,&m); dist[0] = -1; for(int i = 1; i <= n; i++) scanf("%d",&V[i]); for(int i = 1; i <= m; i++) { int t,x,y; scanf("%d",&t); if(t == 1) { scanf("%d%d",&x,&y); if(x == y || V[x] == -1 || V[y] == -1) continue; Merge(find(x),find(y)); } else { scanf("%d",&x); if(V[x] == -1) { printf("-1\n"); } else { int p; p = find(x); printf("%d\n",V[p]); pop(p); } } } return 0; } /* 5 5 1 5 4 2 3 1 1 5 1 2 5 2 2 1 4 2 2 2 */
只想找一个不会伤害我的人