【题目描述】
【思路】
线段树还是写的少,不知道还有这样子的用法
看了别人的题解,这道题是要枚举所有的长度,然后计算把当前长度作为最长桌腿时消耗的最小代价,取最小值就是答案. 当枚举某个长度
i
i
i 时,要把比
i
i
i 长的桌腿都删掉,这个可以用代价的前缀和处理. 然后看一看现在长度为
i
i
i 的桌腿有没有超过剩下桌腿的一半,超过了直接更新答案,如果没超过那么还要删掉一定数量的长度比
i
i
i 小的桌腿,这里用一个线段树来作为一个集合存储长度
<
i
<i
<i 的桌腿的数量以及代价和,线段树的区间表示的意义就是代价,维护的是一段代价区间总和,即桌腿在这个代价区间里的总数量和总代价和,这样可以用查询操作查出代价前
k
k
k 小的桌腿的代价总和
#include<bits/stdc++.h>
#define max(a,b)(a>b?a:b)
#define min(a,b)(a<b?a:b)
#define node tree[id]
#define lson tree[id<<1]
#define rson tree[id<<1|1]
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int maxn=1e5+50;
struct Tree{
int left,right;
int num;
ll sum;
};
int n;
int a[maxn],b[maxn],maxa,maxb;\
vector<int> g[maxn];//g[i]记录长度为i的桌腿代价分别为多少
ll c[maxn],s[maxn];//c[i]是数量前缀和,s[i]是代价前缀和
Tree tree[maxn<<2];
void pushup(int id){
node.num=lson.num+rson.num;
node.sum=lson.sum+rson.sum;
}
void build(int id,int le,int ri){
node.left=le;
node.right=ri;
node.num=0;
node.sum=0;
if(le==ri) return;
int mid=(le+ri)>>1;
build(id<<1,le,mid);
build(id<<1|1,mid+1,ri);
}
void update(int id,int d){//增加一个代价为d的桌腿
if(node.left==node.right){
++node.num;
node.sum+=d;
return;
}
int mid=(node.left+node.right)>>1;
if(d<=mid) update(id<<1,d);
else update(id<<1|1,d);
pushup(id);
}
ll query(int id,int k){//查出当前线段树中代价前k小的桌腿的代价总和
if(node.left==node.right){
return 1LL*node.left*k;
}
int mid=(node.left+node.right)>>1;
if(lson.num==k)
return lson.sum;
else if(lson.num<k)
return lson.sum+query(id<<1|1,k-lson.num);
else
return query(id<<1,k);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
maxa=max(maxa,a[i]);
++c[a[i]];
}
for(int i=1;i<=n;++i){
scanf("%d",&b[i]);
maxb=max(maxb,b[i]);
s[a[i]]+=b[i];
g[a[i]].push_back(b[i]);
}
for(int i=1;i<=maxa;++i){
c[i]+=c[i-1];
s[i]+=s[i-1];
}
build(1,1,maxb);
ll ans=inf;
for(int i=1;i<=maxa;++i){//枚举所有长度,计算答案,取最小值
ll tmp=s[maxa]-s[i];
if(2*g[i].size()>c[i]){//数目足够多,不用删比它小的
ans=min(ans,tmp);
}
else{//需要删k个
int k=c[i]-2*g[i].size()+1;
ans=min(ans,tmp+query(1,k));
}
for(int j=0;j<g[i].size();++j){//将当前长度的桌腿加入线段树
update(1,g[i][j]);
}
}
printf("%lld\n",ans);
return 0;
}