• 简单的堆



    STL的使用方法

    假设有一个 struct, 名为 node, 它的小于号是这样的:

    bool operator<(node s1, node s2) {return //balabala;}

    然后创建一个 priority_queue, 这样创建: priority_queue<node> Q;

    但是 prioity_queue 默认是大根堆, 所以如果想用小根堆, 就要把小于号定义为

    bool operator<(node s1, node s2) {return !(//balabala);}

    即把 bool 值在外面套个取反。

    二叉堆

    
    
    // bigger top_element heap
    int h[N], n;
    void up(int p) { for(;p;p>>=1) if(h[p]>h[p>>1])swap(h[p],h[p<<1]); else break; }
    void down(int p) {
    	for(int q=p<<1; q<=n; p=q,q=p<<1) {
    		if(q<n && h[q|1]>h[q]) q|=1;
    		if(h[q]>h[p]) swap(h[p],h[q]); else break;
    	}
    }
    void ins(int val) {h[++n]=val; up(n);}
    int top() {return h[1];}
    void pop() {h[1]=h[n--]; down(1);}
    
    // advanced skill : remove a element of heap with index (not must root)
    // because a element can't be "up" while it must be "down",  and can't be "down"
    // while it must be "up"
    void remove(int k) {
    	heap[k] = heap[n--];
    	up(k), down(k);
    }
    
    //advanced skill : remove a element of heap with value (not must root)
    // use lazy deleting, creat another heap, who bigger while this heap is bigger, 
    // push elements were wanted to delete, then you can know if the top of the original
    // heap must be delteted
    
    
    // luogu P3378
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int T;
    int h[1001000], n;
    void up(int p) {for(;p;p>>=1) if(h[p>>1]>h[p])swap(h[p],h[p>>1]); else break; }
    void down(int p) {
        for(int q=p<<1; q<=n; p=q, q=p<<1) {
            if(q<n && h[q|1] < h[q]) q|=1;
            if(h[p] > h[q]) swap(h[p], h[q]); else break;
        }
    }
    void ins(int val) {h[++n]=val; up(n);}
    int top() {return h[1];}
    void pop() {h[1]=h[n--]; down(1);}
    
    int main(){
    	scanf("%d", &T);
    	 for(int i=1,a,x;i<=T;++i){
    	 	scanf("%d",&x);
    	 	switch(x){
    	 		case 1:scanf("%d",&a);ins(a);break;
    	 		case 2:printf("%d
    ",top());break;
    	 		case 3:pop();break;
    		 }
    	 }
    	 return 0;
    }
    

    至于这个怎么存结构体, 挺显然的不用我多说了。

    左偏树

    待补。

    Huffman编码

    这部分我是抄的 lydrainbowcat 的 《进阶指南》, 安利一下, 书名全名叫《算法竞赛进阶指南》, 作者是李煜东, 对于提高选手,这书的动态规划和图论部分十分值得一读。

    考虑这样一个问题:构造一棵包含 n 个叶节点的 k 叉树, 其中第 i 个叶子节点带有权值 (w_i), 要求最小化 (sum w_i*dep_i), 其中 (dep_i) 表示第 i 个叶子节点到根节点的距离。该问题的解被称为 k 叉 Huffman 树(哈夫曼树)。

    为了最小化 (sum w_i*dep_i) 应该让权值较大的叶子节点深度尽量小。

    当 k=2 时, 可以用如下算法来求出二叉 Huffman 树:

    1. 建立一个小根堆, 插入这 n 个叶子节点的权值
    2. 从堆中取出最小的两个权值 (w_1)(w_2), 令 (ans += w_1+w_2)
    3. 建立一个权值为 (w_1+w_2) 的树节点 (p), 令 (p) 成为权值为 (w_1)(w_2) 的树节点的父亲
    4. 在堆中插入权值 (w_1+2_2)
    5. 重复第 (2 ext ~4) 步, 直到堆的大小为 1。

    最后, 由所有新建的 p 与原来的叶子节点构成的树就是 Huffman 树, 变量 ans 就是 (sum w_i*dep_i) 的最小值。

    对于 k > 2 的情况, 如果 "推广" k=2 时的做法, 在进行最后一轮循环时, 如果堆的大小在 ([2,k-1]) 之间, 那么整个 Huffman 树的根的子节点的个数小于 k, 显然不是最优解。

    因此, 要人为添加一些权值为 0 的叶子节点, 使得最后叶子节点的总数 n 满足 ((n-1)mod (k-1) = 0), 这就是让子节点不足 k 个的情况发生在最底层, 而不是根节点处。

    (对于这个式子的解释, 可以看成要减少 n-1 个节点, 每次减少 k-1 个节点)

  • 相关阅读:
    slf4j+log4j2的配置
    日志规约
    log4j2配置文件log4j2.xml详解(转载)
    好用的打包工具webpack
    gulp插件
    学习自动化工具gulp
    git
    nodejs学习随笔
    好用的meta标签
    小问题记录
  • 原文地址:https://www.cnblogs.com/tztqwq/p/13797319.html
Copyright © 2020-2023  润新知