左偏树(可并堆)

可并堆就是一种可以支持合并操作的堆,满足堆的性质,主要就是还要满足左子树比右子树要长,然后就直接进行合并操作的时候,直接连在上一个的右子树就行了。然后每次交换一下两个子树的位置(左右互换)。

直接粘贴板子代码。

#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
*/

 

posted @ 2018-07-18 11:33  DukeLv  阅读(153)  评论(0编辑  收藏  举报