左偏树

更推荐启发式合并,好写多了

主要是这个可以持久化

#include<bits/stdc++.h>
#define F(i0,i1,i2) for(int i0=(i1);i0<=(i2);++i0)
#define fr first
#define sc second
#define int long long
#define pii pair<int,int>
using namespace std;
inline int rd(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return f?-x:x;
}
const int N=1e5+7,mod=998244353,inf=1ll<<60;
int n,m;
struct Node{
    int v,rt,d;
    int rs,ls;
}tr[N];
int fnd(int x){return tr[x].rt==x?x:tr[x].rt=fnd(tr[x].rt);}
int mer(int x,int y){
    if(!x||!y)return x|y;
    if(tr[x].v>tr[y].v||(tr[x].v==tr[y].v&&x>y))swap(x,y);//后面的这半部分是因为要先删除编号小的节点
    tr[x].rs=mer(tr[x].rs,y);
    if(tr[tr[x].rs].d>tr[tr[x].ls].d)swap(tr[x].ls,tr[x].rs);//保证左偏
    tr[x].rt=tr[tr[x].ls].rt=tr[tr[x].rs].rt=x;
    tr[x].d=tr[tr[x].rs].d+1;
    return x;
}
int del[N];
void pop(int x){
    tr[x].v=-1;//废除节点
    tr[tr[x].ls].rt=tr[x].ls;
    tr[tr[x].rs].rt=tr[x].rs;
    tr[x].rt=mer(tr[x].ls,tr[x].rs);
}
signed main(){
    n=rd(),m=rd();
    F(i,1,n)tr[i].v=rd(),tr[i].rt=i;
    while(m--){
        int op=rd();
        if(op==1){
            int x=rd(),y=rd();
            if(tr[x].v==-1||tr[y].v==-1)continue;
            int fx=fnd(x),fy=fnd(y);
            if(fx!=fy)tr[fx].rt=tr[fy].rt=mer(fx,fy);
        }
        else {
            int x=rd();
            if(tr[x].v==-1){
                cout<<-1<<'\n';
                continue;
            }
            cout<<tr[fnd(x)].v<<'\n';
            pop(fnd(x));
        }
    }
    return 0;
}
posted @ 2023-09-09 17:09  ussumer  阅读(17)  评论(0)    收藏  举报