令$tot_{i}$为区间$[l,r]$中满足$a_{j}=i$的$j$的个数,将所有非0的$tot_{i}$取出,得到可重集$S$

显然,有以下贪心:不断取出$S$中最小的两个元素,删除这两个元素并加入这两个元素的和,直至$|S|=1$,每一次两个元素的和的和即为答案

使用莫队可以在$o(n\log n)$的时间内得到$S$,但上述过程暴力的复杂度为$o(n\log n)$,无法通过

设置阈值$B$,考虑将上述过程分为两部分——$S$中存在元素$\le B$和$S$中所有元素都$>B$

在第一个部分中,我们可以记录$\le B$的每一个元素的个数,并根据奇偶性简单处理即可(特别的,若恰存在一个元素$\le B$,可以看作所有元素都$>B$),复杂度为$o(B)$

在第二个部分中,显然元素个数不超过$\frac{n}{B}$,直接用上述过程即可,复杂度为$o(\frac{n\log n}{B})$

取$B=\sqrt{n\log n}$即可,总复杂度为$o(n\sqrt{n\log n})$,可以通过

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 100005
4 #define ll long long
5 struct Query{
6 int x,y,id;
7 }q[N];
8 multiset<ll>S,S0;
9 int K,B,n,m,a[N],tot[N],sum[N],sum0[N];
10 ll ans[N];
11 bool cmp(Query x,Query y){
12 return (x.x/K<y.x/K)||(x.x/K==y.x/K)&&(x.y<y.y);
13 }
14 void add_times(int x){
15 if (x<=B)sum[x]++;
16 else S.insert(x);
17 }
18 void dec_times(int x){
19 if (x<=B)sum[x]--;
20 else S.erase(S.find(x));
21 }
22 void update_val(int x,int p){
23 dec_times(tot[x]);
24 tot[x]+=p;
25 add_times(tot[x]);
26 }
27 ll calc(){
28 ll ans=0;
29 S0=S;
30 for(int i=1;i<=B;i++)sum0[i]=sum[i];
31 int lst=0;
32 for(int i=1;i<=B;i++){
33 if (!sum[i])continue;
34 if (lst){
35 sum[i]--;
36 add_times(lst+i);
37 ans+=lst+i;
38 lst=0;
39 }
40 ans+=1LL*(sum[i]/2)*(2*i);
41 if (2*i<=B)sum[2*i]+=sum[i]/2;
42 else{
43 for(int j=1;j<=sum[i]/2;j++)S.insert(2*i);
44 }
45 if (sum[i]&1)lst=i;
46 }
47 if (lst)S.insert(lst);
48 while (S.size()>1){
49 int x=(*S.begin());
50 S.erase(S.begin());
51 int y=(*S.begin());
52 S.erase(S.begin());
53 ans+=x+y;
54 S.insert(x+y);
55 }
56 S=S0;
57 for(int i=1;i<=B;i++)sum[i]=sum0[i];
58 return ans;
59 }
60 int main(){
61 scanf("%d",&n);
62 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
63 K=(int)sqrt(n),B=(int)sqrt(n*log2(n));
64 scanf("%d",&m);
65 for(int i=1;i<=m;i++){
66 scanf("%d%d",&q[i].x,&q[i].y);
67 q[i].id=i;
68 }
69 sort(q+1,q+m+1,cmp);
70 int x=1,y=0;
71 for(int i=1;i<=m;i++){
72 while (q[i].x<x)update_val(a[--x],1);
73 while (y<q[i].y)update_val(a[++y],1);
74 while (x<q[i].x)update_val(a[x++],-1);
75 while (q[i].y<y)update_val(a[y--],-1);
76 ans[q[i].id]=calc();
77 }
78 for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
79 }

[cf700D]Huffman Coding on Segment的更多相关文章

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

    [题目]D. Huffman Coding on Segment [题意]给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长.1<=n,m,ai<=10^5. [算法]哈夫曼树+莫 ...

  2. Codeforces 700D - Huffman Coding on Segment(莫队+根分)

    Codeforces 题目传送门 & 洛谷题目传送门 好家伙,刚拿到此题时我连啥是 huffman 编码都不知道 一种对 \(k\) 个字符进行的 huffman 编码的方案可以看作一个由 \ ...

  3. hdu 1053 (huffman coding, greedy algorithm, std::partition, std::priority_queue ) 分类: hdoj 2015-06-18 19:11 22人阅读 评论(0) 收藏

    huffman coding, greedy algorithm. std::priority_queue, std::partition, when i use the three commente ...

  4. [IR] Huffman Coding

    为了保证:Block中,所有的叶子在所有的中间结点的前面.Static: Huffman coding Dynamic: Adaptive Huffman 一些概念 压缩指标 • Compress a ...

  5. 霍夫曼编码(Huffman Coding)

    霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符 ...

  6. 哈夫曼编码(Huffman coding)的那些事,(编码技术介绍和程序实现)

    前言 哈夫曼编码(Huffman coding)是一种可变长的前缀码.哈夫曼编码使用的算法是David A. Huffman还是在MIT的学生时提出的,并且在1952年发表了名为<A Metho ...

  7. <Sicily>Huffman coding

    一.题目描述 In computer science and information theory, a Huffman code is an optimal prefix code algorith ...

  8. 哈夫曼编码的理解(Huffman Coding)

    哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最 ...

  9. Huffman coding & Huffman tree

    Huffman coding & Huffman tree Huffman coding 哈夫曼编码 / 最优二元前缀码 Huffman tree 哈夫曼树 / 最优二叉树 https://w ...

随机推荐

  1. C语言日记② 初识 C的内存

    第一节: 上一个笔记 有趣的恶搞小程序 定时关机 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <str ...

  2. 无法解析的外部符号"void_cdecl caffe::caffe_gpu_dot<double>(int,double........)"

    将源码中的.cu文件添加到项目中即可,即使创建的就是NVIDIA的项目,也需要把这些个.cu文件添加进来

  3. Ajax样例

    $.ajax({ url : "newsservlet",//请求地址 dataType : "json",//数据格式 type : "post&q ...

  4. C 编译预处理和宏

    前置知识 0x00 cmd编译运行程序 https://blog.csdn.net/WWIandMC/article/details/106265734 0x01 --save-temps gcc m ...

  5. Linux主机入侵检测

    检查系统信息.用户账号信息 ● 操作系统信息 cat /proc/version 用户信息 用户信息文件 /etc/passwd root:x:0:0:root:/root:/bin/bash 用户名 ...

  6. [技术博客] 利用SharedPreferences来实现登录状态的记忆功能

    [技术博客] 利用SharedPreferences来实现登录状态的记忆功能 一.SharedPreferences简介 SharedPreferences是Android平台上一个轻量级的存储辅助类 ...

  7. 【二食堂】Alpha - 事后分析

    事后分析 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? Alpha阶段要解决的问题是:根据用户标注的信息完成知识图谱的生成渲染.要解决的问题定义得比较 ...

  8. oo第三单元学习总结

    OO第三单元小结 一.JML语言理论基础及工具链梳理 在本单元我们学习了JML语言的一些基础知识,能够让我们看懂简单的JML规格并写出对应代码, 主要用到的知识点有:   1.requires 该子句 ...

  9. 搬运1:关于对C语言中数组名取地址加减等操作的一点探究

    对于数组名取地址强制转换的操作 偶然在晚上学了C语言指针后网页闲逛找题时,被一个数组名取地址搞糊涂了,在自己试验加探索后我稍微悟了一点东西. 代码如下: #include<stdio.h> ...

  10. 正则表达式匹配 牛客网 剑指Offer

    正则表达式匹配 牛客网 剑指Offer 题目描述 请实现一个函数用来匹配包括'.'和''的正则表达式.模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次). 在本题中, ...