可以合并的堆。。。板子题
以dis记录节点能向右走的最大距离
此结构维护左子树所有dis大于等于右子树的dis。。
题目:
如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:
操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)
操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)
so 代码。。。
#include<cstdio> #include<cstring> #include<iostream> #include<cctype> using namespace std; #define love_nmr 0 #define olinr return #define nmr 150505 int son[nmr][2]; int fa[nmr]; int dis[nmr]; int val[nmr]; int n,m; inline int read() { int f=1,x=0; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } olinr x*f; } inline void put(int x) { if(x<0) { x=-x; putchar('-'); } if(x>9) put(x/10); putchar(x%10+'0'); } inline int findset(int x) { while(fa[x]) x=fa[x]; olinr x; } inline void swap(int &a,int &b) { int temp=a; a=b; b=temp; } inline int merge(int x,int y) { if(!x||!y) return x+y; if(val[x]>val[y]||(val[x]==val[y]&&x>y)) swap(x,y); son[x][1]=merge(son[x][1],y); fa[son[x][1]]=x; if(dis[son[x][0]]<dis[son[x][1]]) swap(son[x][0],son[x][1]); dis[x]=dis[son[x][1]]+1; olinr x; } inline void pop(int x) { val[x]=-1; fa[son[x][0]]=fa[son[x][1]]=0; merge(son[x][0],son[x][1]); } int main() { n=read(); m=read(); for(int i=1;i<=n;i++) val[i]=read(); int flag,x,y; while(m--) { flag=read(); if(flag==1) { x=read(); y=read(); if(val[x]==-1||val[y]==-1||x==y) continue; int xx=findset(x); int yy=findset(y); merge(xx,yy); } else { x=read(); if(val[x]==-1) { cout<<-1<<endl; continue; } y=findset(x); cout<<val[y]<<endl; pop(y); } } olinr love_nmr; }