【CodeForces】700 D. Huffman Coding on Segment 哈夫曼树+莫队+分块

【题目】D. Huffman Coding on Segment

【题意】给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长。1<=n,m,ai<=10^5。

【算法】哈夫曼树+莫队+分块

【哈夫曼树】哈夫曼树又称最优构造树,n个数字的哈夫曼树是含有n个给定权值叶子的点权路径和最小的二叉树。

点权路径和(WPL)可以表示为每个点的深度*权值

构造方法:每次取点权最小的两个根节点作为左右子树(左小右大)组成新根节(点权为左右之和),多次操作直到只剩一棵树。(类似合并果子)

哈夫曼树的WPL是所有节点的权值和-数字和(也是非叶子节点的权值和,或是所有非根节点的权值和)。

哈夫曼编码:从根出发左0右1,走到每个字符的二进制就是它的编码。

Huffman Code是电文总长最短的二进制编码方式,将n个字符的出现频率作为点权构造哈夫曼树得到的就是对应的哈夫曼编码。

n个数字的哈夫曼编码长度和就是WPL。

【题解】对于一个区间,令f[x]表示数字x的出现次数,令g[x]表示出现次数为x的数字个数,用莫队维护。

每次区间询问,考虑朴素做法是将出现次数作为点权,构造哈夫曼树,但这样太慢了。令S=sqrt(n)。

对于出现次数>S的数字,一共只有不超过S个,按朴素做法构造哈夫曼树求解即可,复杂度O(S log S)。

对于出现次数<S的数字,考虑到点权很小,可以用一个桶记录,就可以批量做了,复杂度O(S),点权一旦超过S就进入上一过程。

总复杂度O(n√n)。

 

posted @ 2018-04-16 14:50  ONION_CYC  阅读(175)  评论(0编辑  收藏