题目描述
如题,一开始有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所得的结果。
裸题吧,附上模板。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 8 const int NN=1e5+7; 9 10 int n,m,a[NN]; 11 int r[NN],l[NN],d[NN],fa[NN]; 12 bool died[NN]; 13 14 int find(int num) 15 { 16 if (fa[num]!=num) return find(fa[num]); 17 return num; 18 } 19 int merge(int x,int y) 20 { 21 if (!x) return y; 22 if (!y) return x; 23 if (a[x]>a[y]) swap(x,y); 24 r[x]=merge(r[x],y); 25 fa[r[x]]=x; 26 if (d[r[x]]>d[l[x]]) swap(r[x],l[x]); 27 d[x]=d[r[x]]+1; 28 return x; 29 } 30 int main() 31 { 32 scanf("%d%d",&n,&m); 33 for (int i=1;i<=n;i++) 34 { 35 fa[i]=i; 36 scanf("%d",&a[i]); 37 } 38 for (int i=1;i<=m;i++) 39 { 40 int k,u,v; 41 scanf("%d",&k); 42 if (k==1) 43 { 44 scanf("%d%d",&u,&v); 45 if (died[u]||died[v]) continue; 46 int x=find(u),y=find(v); 47 if (x!=y) 48 { 49 int t=merge(x,y); 50 fa[t]=t; 51 } 52 } 53 else 54 { 55 scanf("%d",&u); 56 int x=find(u); 57 if (died[x]) printf("-1\n"); 58 else 59 { 60 printf("%d\n",a[x]); 61 died[x]=1; 62 int t=merge(r[x],l[x]); 63 fa[t]=t; 64 } 65 } 66 } 67 }
时间: 2024-11-10 07:35:56