把长度为d的桌腿当作最长桌腿,则要砍掉比d大的所有桌腿,假设剩下k个桌腿,长度为d的桌腿有m个,若k >= 2 *m则要利用线段树找到最小的k - (2 *m - 1)个桌腿,砍掉
#include <bits/stdc++.h>
#define maxn 100005
#define MOD 1000000007
using namespace std;
typedef long long ll;
struct Node{
int l, d;
int i;
}node[maxn];
int cnt[maxn<<2], sum[maxn<<2];
int d[maxn];
bool cmp1(const Node&a, const Node&b){
return a.d < b.d;
}
bool cmp2(const Node&a, const Node&b){
return a.l < b.l;
}
void Update(int n, int e, int l, int r, int k){
if(l == r){
cnt[n]++;
sum[n] += k;
return ;
}
int mid = (l + r) >> 1;
if(e <= mid)
Update(n<<1, e, l, mid, k);
else
Update(n<<1|1, e, mid+1, r, k);
cnt[n] = cnt[n<<1] + cnt[n<<1|1];
sum[n] = sum[n<<1] + sum[n<<1|1];
}
int Query(int n, int l, int r, int p){
if(l == r){
return sum[n];
}
int mid = (l + r) >> 1;
if(cnt[n<<1] >= p)
return Query(n<<1, l, mid, p);
return sum[n<<1] + Query(n<<1|1, mid+1, r, p - cnt[n<<1]);
}
int main(){
// freopen("in.txt", "r", stdin);
int n, mins = 1e9;
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &node[i].l);
for(int i = 0; i < n; i++)
scanf("%d", &node[i].d);
sort(node, node+n, cmp1);
for(int i = 0; i < n; i++)
node[i].i = i;
sort(node, node+n, cmp2);
for(int i = n-1; i >= 0; i--)
d[i] = d[i+1] + node[i].d;
int h = 0;
for(int i = 1; i <= n; i++){
if(node[i].l != node[i-1].l){
if(i - h == 1){
mins = min(mins, d[0] - node[h].d);
}
else{
if(i - h == 2)
mins = min(mins, d[0] - node[h].d - node[h+1].d);
int dd = i - h;
if(2 * dd > i)
mins = min(mins, d[i]);
else{
int e = i - (2 * dd - 1);
int h = Query(1, 0, n-1, e);
mins = min(mins, h + d[i]);
}
}
for(int j = h; j < i; j++){
Update(1, node[j].i, 0, n-1, node[j].d);
}
h = i;
}
}
printf("%d\n", mins);
return 0;
}