标签:第一个 简单 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 }
[cf700D]Huffman Coding on Segment
标签:第一个 简单 alc print closed div 区间 view clu
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14962997.html