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 树:
- 建立一个小根堆, 插入这 n 个叶子节点的权值
- 从堆中取出最小的两个权值 (w_1) 和 (w_2), 令 (ans += w_1+w_2)。
- 建立一个权值为 (w_1+w_2) 的树节点 (p), 令 (p) 成为权值为 (w_1) 和 (w_2) 的树节点的父亲
- 在堆中插入权值 (w_1+2_2)
- 重复第 (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 个节点)