zoukankan      html  css  js  c++  java
  • 左偏树(可并堆)

    说是左偏树,其实叫可并堆更合理

    对一个节点来说,它的左右子树的值都要大于它自己的值

    定义距离 (dis) : 每个节点到空节点的距离

    左偏树有一个重要的性质:

    • 每个子树的左儿子的 (dis) 要大于等于 右儿子的 (dis) ,所以直觉上来说就是

    “左偏”

    • 插入 : (O(log n))
    • 求最小值: (O(1))
    • 删除最小值: (O(log n))
    • 合并两棵树(O(log n))

    P3377 【模板】左偏树(可并堆) - 洛谷

    /*
     * @Author: zhl
     * @Date: 2020-11-21 11:16:27
     */
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 2e5 + 10;
    
    int l[N], r[N], v[N], fa[N], idx, dis[N];
    
    int find(int a) {
    	return a == fa[a] ? a : fa[a] = find(fa[a]);
    }
    bool cmp(int a, int b) {
    	if (v[a] != v[b])return v[a] < v[b];
    	return a < b;
    }
    int merge(int a, int b) {
    	if (!a or !b)return a + b;
    	if (cmp(b, a))swap(a, b);
    	r[a] = merge(r[a], b);
    	if (dis[r[a]] > dis[l[a]])swap(l[a], r[a]);
    	dis[a] = dis[r[a]] + 1;
    	return a;
    }
    int n;
    int main() {
    	v[0] = 2e9;
    	scanf("%d", &n);
    	while (n--) {
    		int op, a, b;
    		scanf("%d%d", &op, &a);
    		if (op == 1) {
    			v[++idx] = a;
    			dis[idx] = 1;
    			fa[idx] = idx;
    		}
    		else if (op == 2) {
    			scanf("%d", &b);
    			a = find(a), b = find(b);
    			if (a != b) {
    				if (cmp(b, a)) swap(a, b);
    				fa[b] = a;
    				merge(a, b);
    			}
    		}
    		else if (op == 3) {
    			printf("%d
    ", v[find(a)]);
    		}
    		else {
    			a = find(a);
    			if (cmp(r[a], l[a]))swap(l[a], r[a]);
    			fa[a] = l[a]; fa[l[a]] = l[a];
    			merge(l[a], r[a]);
    		}
    	}
    }
    
  • 相关阅读:
    Lucky Permutation Triple 构造
    HDU4283:You Are the One(区间DP)
    D. Match & Catch 后缀数组
    数学选讲 orz
    D
    一步一步线段树
    湖科大校赛第三题
    最大流部分
    bfs题目集锦
    hdu1429 bfs+状态压缩
  • 原文地址:https://www.cnblogs.com/sduwh/p/14034227.html
Copyright © 2011-2022 走看看