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

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

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

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

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

code:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>

using namespace std;

const int wx=200017;

inline int read(){
    int sum=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    return sum*f;
}

int n,m;
int val[wx],f[wx],dis[wx];
int ch[wx][3];

int merge(int x,int y){
    if(x==0||y==0) return x+y;
    if((val[x]>val[y])||(val[x]==val[y]&&x>y))swap(x,y);
    ch[x][1]=merge(ch[x][1],y); f[ch[x][1]]=x;
    if(dis[ch[x][1]]>dis[ch[x][0]])swap(ch[x][1],ch[x][0]);
    dis[x]=dis[ch[x][1]]+1; return x;
}

int getf(int x){
    while(f[x])x=f[x];
    return x;
}

void pop(int x){
    val[x]=-1;
    f[ch[x][1]]=f[ch[x][0]]=0;
    merge(ch[x][0],ch[x][1]);
}

int main(){
    n=read(); m=read();
    for(int i=1;i<=n;i++) val[i]=read();
    for(int i=1;i<=m;i++){
        int opt; opt=read();
        if(opt==1){
            int x,y; x=read(); y=read();
            if(x==y||val[x]==-1||val[y]==-1)continue;
            int fx=getf(x); int fy=getf(y);
            merge(fx,fy);
        }
        else{
            int x; x=read();
            if(val[x]==-1)puts("-1");
            else{
                int fx=getf(x); 
                printf("%d\n",val[fx]); pop(fx);
            }
        }
    }
}
posted @ 2018-10-27 06:28  _王小呆  阅读(140)  评论(0编辑  收藏  举报