码迷,mamicode.com
首页 > 其他好文 > 详细

[cf700D]Huffman Coding on Segment

时间:2021-07-02 16:41:05      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:第一个   简单   alc   print   closed   div   区间   view   clu   

令$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 }
View Code

 

[cf700D]Huffman Coding on Segment

标签:第一个   简单   alc   print   closed   div   区间   view   clu   

原文地址:https://www.cnblogs.com/PYWBKTDA/p/14962997.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!