鸽鸽

  • Code Level: ※※
  • Thinking Level: ※※

Description

很不幸,蔡老师最后还是鸽了。愤怒的网友们冲进了蔡老师的家里,蔡老师不得不向网友们道歉。
n个网友的愤怒值为f1,f2,…,fn当蔡老师向第i个网友道j次歉,第i网友的愤怒值会变成⌊fi/2^j⌋。蔡老师希望一共道歉k次使得网友们的愤怒值之和最小。
蔡老师希望你能回答,对于[l,r]这一段网友fl,fl+1,…,fr,道歉一共k次,这些网友们的愤怒值之和最小是多少。

Solution

k次道歉贪心地想一定是要道贡献最大的k次歉的,所以可以对所有fi对于道不同的歉构建主席树,查询前k大的贡献就可以了
而一个针对时间和空间的优化是,我们把值域分块,算出道歉i次在不同值域中的贡献,我们便可以优化从查询k变成查询k剔除了包含块的p,而进入主席树的次数也因此减少了

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int nn=100005;
const int inf=5e8+5;
int n,q,a[nn];
struct dat{
int l,r,k;ll ans;
}e[nn*5];
ll aa[35][nn],sum[35][nn],ned[35][nn],ss[nn];
vector<int>g[35];
ll val[nn*50],sz[nn*50];
int tot,rt[nn],tr[nn*50][2];
void inse(int &x,int y,int l,int r,int p){
x=++tot; sz[x]=sz[y]+1; val[x]=val[y]+p; tr[x][0]=tr[y][0]; tr[x][1]=tr[y][1];
if(l+1==r) return ;
int mid=l+r>>1;
if(mid>p) inse(tr[x][0],tr[y][0],l,mid,p);
else inse(tr[x][1],tr[y][1],mid,r,p);
}
ll qurt(int x,int y,int l,int r,int k){
if(sz[x]-sz[y]<=k) return val[x]-val[y];
if(l+1==r) return 1ll*l*k;
int mid=l+r>>1,rs=sz[tr[x][1]]-sz[tr[y][1]];
if(rs>=k) return qurt(tr[x][1],tr[y][1],mid,r,k);
else return val[tr[x][1]]-val[tr[y][1]]+qurt(tr[x][0],tr[y][0],l,mid,k-rs);
}
void cle(){
int i;
for(i=1;i<=1;i++) tr[i][0]=tr[i][1]=val[i]=sz[i]=0;
tot=0;
}
int main(){
int i,j,t;
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++){
scanf("%d",&a[i]); t=a[i]; ss[i]=ss[i-1]+a[i];
for(j=31;j>=0;j--){
if(a[i]>>j){
aa[j][i]=sum[j][i]=t-t/2;
ned[j][i]=1;
t>>=1;
}
sum[j][i]+=sum[j][i-1]; ned[j][i]+=ned[j][i-1];
}
}
for(i=1;i<=q;i++){
scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].k);
e[i].ans=ss[e[i].r]-ss[e[i].l-1];
for(j=31;j>=0;j--){
t=ned[j][e[i].r]-ned[j][e[i].l-1];
if(t>e[i].k) break ;
e[i].k-=t; e[i].ans-=sum[j][e[i].r]-sum[j][e[i].l-1];//printf("%d %d %d<\n",e[i].ans,e[i].k,sum[j][e[i].r]-sum[j][e[i].l-1]);
}
if(j>=0&&e[i].k>0) g[j].push_back(i);

}
for(j=31;j>=0;j--)if(g[j].size()){
cle();
for(i=1;i<=n;i++) inse(rt[i],rt[i-1],1,inf,aa[j][i]);
for(i=0;i<g[j].size();i++)
e[g[j][i]].ans-=qurt(rt[e[g[j][i]].r],rt[e[g[j][i]].l-1],1,inf,e[g[j][i]].k);
}
for(i=1;i<=q;i++) printf("%lld\n",e[i].ans);
return 0;
}