码迷,mamicode.com
首页 > 其他好文 > 详细

【模板】左偏树(可并堆)

时间:2017-12-29 18:58:55      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:out   操作   http   维护   namespace   col   表示   gpo   font   

https://www.luogu.org/problemnew/show/3377

 

主要是删除堆顶元素后并查集关系的维护:

第一种方式(代码):

原来的堆顶是x,删除x后,合并x的左右子树l、r,新的堆顶为y

则令x的祖先指向y

堆顶的直接子节点在并查集中的祖先指向堆顶

这样在寻找l、r的祖先时,先找到x,再找到y

x实际已经删除,但保留在并查集中,充当l、r找祖先节点的桥梁

第二种方式:

并查集不路径压缩

删除x后,l的祖先指向l,r的祖先指向r

 

 

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001

using namespace std;

struct node
{
    int lc,rc;
    int key,dis;
}e[N];

int fa[N];

bool cut[N];

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c==-) f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-0; c=getchar(); }
    x*=f;
}

int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }

int merge(int a,int b)
{
    if(!a) return b;
    if(!b) return a;
    if(e[a].key>e[b].key) swap(a,b);
    e[a].rc=merge(e[a].rc,b);
    if(e[e[a].rc].dis>e[e[a].lc].dis) swap(e[a].lc,e[a].rc);
    if(!e[a].rc) e[a].dis=0;
    else e[a].dis=e[e[a].rc].dis+1;
    return a;
}

void erase(int x)
{
    cut[x]=true;
    fa[x]=merge(e[x].lc,e[x].rc);
    fa[fa[x]]=fa[x];
}

int main()
{
    int n,m;
    read(n); read(m);
    for(int i=1;i<=n;++i) 
    {
        read(e[i].key);
        fa[i]=i;
    }
    int ty,x,y;
    while(m--)
    {
        read(ty);
        if(ty==1)
        {
            read(x);
            read(y);
            if(cut[x]||cut[y]) continue;
            x=find(x);
            y=find(y);
            if(x!=y) fa[x]=fa[y]=merge(x,y);
        }
        else
        {
            read(x);
            if(cut[x]) { puts("-1"); continue; }
            x=find(x);
            cout<<e[x].key<<\n;
            erase(x);
        }
    }
}

 

题目描述

如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:

操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)

操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)

输入输出格式

输入格式:

 

第一行包含两个正整数N、M,分别表示一开始小根堆的个数和接下来操作的个数。

第二行包含N个正整数,其中第i个正整数表示第i个小根堆初始时包含且仅包含的数。

接下来M行每行2个或3个正整数,表示一条操作,格式如下:

操作1 : 1 x y

操作2 : 2 x

 

输出格式:

 

输出包含若干行整数,分别依次对应每一个操作2所得的结果。

【模板】左偏树(可并堆)

标签:out   操作   http   维护   namespace   col   表示   gpo   font   

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8145758.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!