题解:
左偏树,一棵向左倾斜的二叉树。
板子:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int n,m,fa[N],v[N],dis[N],ls[N],rs[N]; 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); rs[x] = merge(rs[x],y); fa[rs[x]] = x; if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]); dis[x] = dis[rs[x]]+1; return x; } int get_top(int x) { while(fa[x])x=fa[x]; return x; } int erase(int x) { if(fa[x]==-1)return -1; x = get_top(x); fa[x] = -1; int u = merge(ls[x],rs[x]); fa[u] = 0; return v[x]; } int main() { read(n),read(m); for(int i=1;i<=n;i++) { read(v[i]); dis[i] = 1; } for(int opt,x,y,i=1;i<=m;i++) { read(opt); if(opt==1) { read(x),read(y); if(fa[x]==-1||fa[y]==-1)continue; int tx = get_top(x),ty = get_top(y); if(tx==ty)continue; int u = merge(tx,ty); fa[u] = 0; }else { read(x); printf("%d ",erase(x)); } } return 0; }
$upd:$
之前版本被$luogu$数据卡掉了,$get_top$操作是$O(n)$的。(0_0)
更新路径压缩的做法。
首先合并两棵树就并一下,删除操作要求删除堆顶元素。
肯定是不能直接删的。
怎么做呢,合并儿子后将自己的指针指向新的堆顶就好了。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; template<typename T> inline void read(T&x) { T f =1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int n,m,ch[N][2],v[N],dep[N],ff[N]; int findrt(int x){return x==ff[x]?x:ff[x]=findrt(ff[x]);} int merge(int x,int y) { if(!(v[x]*v[y]))return x+y; if(v[x]>v[y]||(v[x]==v[y]&&x>y))swap(x,y); ch[x][1] = merge(ch[x][1],y);ff[ch[x][1]]=x; if(dep[ch[x][0]]<dep[ch[x][1]])swap(ch[x][0],ch[x][1]); dep[x]=dep[ch[x][1]]+1; return x; } bool ot[N]; int main() { read(n),read(m); for(int i=1;i<=n;i++) read(v[i]),dep[i]=1,ff[i]=i; for(int op,x,y,i=1;i<=m;i++) { read(op),read(x); if(op==1) { read(y); if(ot[x]||ot[y])continue; x = findrt(x); y = findrt(y); if(x!=y) merge(x,y); }else { if(ot[x]) { puts("-1"); continue; } x = findrt(x); ot[x] = 1; printf("%d ",v[x]); int now = merge(ch[x][0],ch[x][1]); ff[x] = ff[now] = now; } } return 0; }