用线段树查询区间k小和。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100100;
int cnt[MAXN];
struct Leg
{
int l,d;
}arr[MAXN];
bool cmp(Leg l1,Leg l2)
{
return l1.l>l2.l;
}
struct node
{
long long c,v;
}tree[MAXN<<2];
void build(int l,int r,int k)
{
if(l==r)
{
tree[k].c=cnt[l];
tree[k].v=tree[k].c*l;
return;
}
int m=(l+r)>>1;
build(l,m,k<<1);
build(m+1,r,k<<1|1);
tree[k].v=tree[k<<1].v+tree[k<<1|1].v;
tree[k].c=tree[k<<1].c+tree[k<<1|1].c;
}
void update(int l,int r,int k,long long val)
{
tree[k].c--;
tree[k].v-=val;
if(l==r)
return;
int m=(l+r)>>1;
if(val<=m)
update(l,m,k<<1,val);
else
update(m+1,r,k<<1|1,val);
}
long long query(int l,int r,int k,long long num)
{
if(l==r)
return num*l;
int m=(l+r)>>1;
if(tree[k<<1].c>=num)
return query(l,m,k<<1,num);
else
return tree[k<<1].v+query(m+1,r,k<<1|1,num-tree[k<<1].c);
}
int main()
{
long long n,i,j,bef,sum,ans;
while(~scanf("%lld",&n))
{
for(i=1;i<=n;i++)
scanf("%d",&arr[i].l);
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;i++)
{
scanf("%d",&arr[i].d);
cnt[arr[i].d]++;
}
build(1,MAXN,1);
sort(arr+1,arr+n+1,cmp);
ans=1ll<<60;
sum=0;
bef=0;
for(i=1;i<=n;i=j+1)
{
if(sum>ans)
break;
sum+=bef;
bef=arr[i].d;
update(1,MAXN,1,arr[i].d);
for(j=i+1;j<=n&&arr[j].l==arr[i].l;j++)
{
bef+=arr[j].d;
update(1,MAXN,1,arr[j].d);
}
j--;
if(n-j<j-i+1)
{
ans=min(ans,sum);
break;
}
else
ans=min(ans,sum+query(1,MAXN,1,n-j-(j-i)));
}
printf("%lld\n",ans);
}
}