【模板】左偏树(可并堆)

题目描述

如题,一开始有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: 复制
5 5
1 5 4 2 3
1 1 5
1 2 5
2 2
1 4 2
2 2
输出样例#1: 复制
1
2

说明

当堆里有多个最小值时,优先删除原序列的靠前的,否则会影响后续操作1导致WA。

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=1000,M<=1000

对于100%的数据:N<=100000,M<=100000

样例说明:

初始状态下,五个小根堆分别为:{1}、{5}、{4}、{2}、{3}。

第一次操作,将第1个数所在的小根堆与第5个数所在的小根堆合并,故变为四个小根堆:{1,3}、{5}、{4}、{2}。

第二次操作,将第2个数所在的小根堆与第5个数所在的小根堆合并,故变为三个小根堆:{1,3,5}、{4}、{2}。

第三次操作,将第2个数所在的小根堆的最小值输出并删除,故输出1,第一个数被删除,三个小根堆为:{3,5}、{4}、{2}。

第四次操作,将第4个数所在的小根堆与第2个数所在的小根堆合并,故变为两个小根堆:{2,3,5}、{4}。

第五次操作,将第2个数所在的小根堆的最小值输出并删除,故输出2,第四个数被删除,两个小根堆为:{3,5}、{4}。

故输出依次为1、2。

 1 #include<bits/stdc++.h>>
 2 using namespace std;
 3 const int N=100010;
 4 int n,m,val[N],ch[N][2],f[N],d[N],a,x,y;
 5 inline int read(){
 6     int res=0,f=1;
 7     char ch=getchar();
 8     while (ch<'0'||ch>'9'){
 9         if (ch=='-'){
10             f=-f;
11         }
12         ch=getchar();
13     }
14     while (isdigit(ch)){
15         res=res*10+ch-'0';
16         ch=getchar();
17     }
18     return res*f;
19 }
20 inline int merge(int x,int y)
21 {
22     if (x==0||y==0)
23     {
24         return x+y;
25     }
26     if (val[x]>val[y]||(val[x]==val[y]&&x>y))
27     {
28         swap(x,y);
29     }
30     ch[x][1]=merge(ch[x][1],y);
31     f[ch[x][1]]=x;
32     if (d[ch[x][0]]<d[ch[x][1]])
33     {
34         swap(ch[x][0],ch[x][1]);
35     }
36     d[x]=d[ch[x][1]]+1;
37     return x;
38 }
39 
40 inline int get(int x)
41 {
42     while (f[x])
43     {
44         x=f[x];
45     }
46     return x;
47 }
48 
49 inline void pop(int x)
50 {
51     val[x]=-1;
52     f[ch[x][0]]=f[ch[x][1]]=0;
53     merge(ch[x][0],ch[x][1]);
54 }
55 
56 int main()
57 {
58     n=read();m=read();
59     d[0]=-1;
60     for (int i=1; i<=n; i++)
61     {
62         val[i]=read();
63     }
64     for (int i=1; i<=m; i++)
65     {
66         a=read();
67         if (a==1)
68         {
69             x=read();y=read();
70             if(val[x]==-1||val[y]==-1)
71             {
72                 continue;
73             }
74             if (x==y)
75             {
76                 continue;
77             }
78             int f1=get(x),f2=get(y);
79             merge(f1,f2);
80         }
81         else
82         {
83             x=read();
84             if (val[x]==-1)
85             {
86                 printf("-1
");
87             }
88             else
89             {
90                 int f1=get(x);
91                 printf("%d
",val[f1]);
92                 pop(f1);
93             }
94         }
95     }
96 }
View Code
原文地址:https://www.cnblogs.com/Accpted/p/11213269.html