P3377

题目描述

如题,一开始有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
");
58             else
59             {
60                 printf("%d
",a[x]);
61                 died[x]=1;
62                 int t=merge(r[x],l[x]);
63                 fa[t]=t;
64             }
65         }
66     }
67 }
原文地址:https://www.cnblogs.com/fengzhiyuan/p/7471056.html