解析
论文:左偏树的特点及其应用
0. 吐槽
怀疑这题是并查集,,,找根有点烦
以前一直觉得很厉害的样纸,其实还是可以接受的(别和我说证明,不听)
PS:已退役,过来划水
1. 笔记
功能:在
O
(
log
2
n
)
O( \log_{2}n)
O(log2n)内进行堆的合并
核心:key(堆的性质), dis(左偏性质)
关键操作:合并;删除
左偏性质:保证
d
i
s
(
l
c
h
)
≥
d
i
s
(
r
c
h
)
dis(lch) \geq dis(rch)
dis(lch)≥dis(rch),其中
d
i
s
(
p
)
=
d
i
s
(
r
c
h
)
+
1
dis(p) = dis(rch) + 1
dis(p)=dis(rch)+1
…
\dots
…
2. 关于本题
左偏树相关的只有合并操作
关于找根:并查集维护(带路径压缩);将删除点指向合并后的根节点
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define IL inline
using namespace std;
IL int read()
{
int sum = 0;
bool f = 0;
char c = getchar();
for(; '0' > c || c > '9'; c = getchar())
if(c == '-') f = 1;
for(; '0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + (c - '0');
return f ? -sum : sum;
}
const int N(100005);
int n, m;
int ch[N][2], val[N], dis[N], fa[N];
IL int Find(int x)
{
int p = x;
for(; fa[p] != p; p = fa[p]);
for(int tmp; x != p; )
{
tmp = fa[x];
fa[x] = p;
x = tmp;
}
return p;
}
IL int Merge(int x, int y)
{
if(!x) return y;
if(!y) return x;
if(val[x] > val[y]) swap(x, y);
ch[x][1] = Merge(ch[x][1], y);
fa[ch[x][1]] = x;
if(dis[ch[x][0]] < dis[ch[x][1]]) swap(ch[x][0], ch[x][1]);
dis[x] = dis[ch[x][1]] + 1;
return x;
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= n; ++i)
{
val[i] = read(); fa[i] = i;
}
val[0] = -1;
for(int op, x, y; m; --m)
{
op = read(); x = read();
if(op == 1)
{
y = read();
if(val[x] == -1 || val[y] == -1) continue;
x = Find(x); y = Find(y);
if(x == y) continue;
Merge(x, y);
}else
if(op == 2)
{
if(val[x] == -1) { printf("-1\n"); continue; }
x = Find(x);
printf("%d\n", val[x]);
fa[ch[x][0]] = ch[x][0];
fa[ch[x][1]] = ch[x][1];
val[x] = -1;
fa[x] = Merge(ch[x][0], ch[x][1]);
}
}
return 0;
}