$des$
有 $n$ 个物品,第 $i$ 个物品的价格是 $v_i$ ,有两个人,每个人都喜欢 $n$ 个物品中的一些物品。
要求选出正好 $m$ 个物品,满足选出的物品中至少有 $k$ 个物品被第一个人喜欢,$k$ 个物品被第二个人喜欢。并求出最小的价格和。

$sol$
将所有物品分成 $4$ 类
1. $a \cap b$
2. $a - a \cap b$
3. $b - a \cap b$
4. $全集 - a \cup b$

枚举 $1$ 选了多少个
此时 $2, 3$ 选多少个是固定的了
这样的话只需维护剩余元素的前 $x$ 小值之和

对顶堆维护
大根堆维护前 $x$ 小
查询时就是大根堆的权值之和
删除元素标记

维护剩余元素的前 $x$ 小值之和也可以用权值线段树

 

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10;

#define gc getchar()
inline int read() {
    int x = 0; char c = gc;
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x;
}

#define Rep(i, a, b) for(int i = a; i <= b; i ++)
#define LL long long
#define Fin(a) freopen(a, "r", stdin)
#define Fout(a) freopen(a, "w", stdout)
#define E return
#define End cout << "\n"

map <int, int> Map;
int W[N];
int n, m, k, a, b;
bool usea[N], useb[N];

priority_queue <int, vector <int>, less <int> > Big;
priority_queue <int, vector <int>, greater <int> > Small;

int szab[N], jsab;
int sza[N], jsa;
int szb[N], jsb;
int sznot[N], jsnot;
LL sum1[N], sum2[N], sum3[N];

int Size;
LL Sum;

void Update() {
    while(Big.size() && Map[Big.top()]) Map[Big.top()] --, Big.pop();
    while(Small.size() && Map[Small.top()]) Map[Small.top()] --, Small.pop();
}

int Now_size;
int ato, bto, abto;

void Add(int x) {
    Update();
    while(Size < Now_size && Small.size()) {
        int topsmall = Small.top(); Small.pop();
        Size ++, Sum += topsmall, Big.push(topsmall);
    }
    if(Size == Now_size) {
        if(Big.size() == 0) Small.push(x);
        else if(x < Big.top()) {
            int topbig = Big.top();
            Sum += (x - topbig);
            Big.pop(); Big.push(x);
            Small.push(topbig);
        }
        return ;
    }
    if(Size < Now_size) {
        Big.push(x);
        Size ++; Sum += x;
        return ;
    }
    Update();
    int topbig = Big.top();
    if(x < topbig) {
        Sum += (x - topbig);
        Big.pop(); Big.push(x);
        Small.push(topbig); 
    } else {
        Small.push(x);
    }
}

bool Judge() {
    if(m < k) return 1;
    if(jsab + jsa < k || jsab + jsb < k) return 1;
    if(k * 2 - jsab > m) return 1;
    return 0;
}

void RE() {
    cout << "error" << "\n";
}

void Bef_work() {
    Rep(i, 1, n) {
        if(usea[i] && useb[i]) szab[++ jsab] = W[i];
        else if(usea[i]) sza[++ jsa] = W[i];
        else if(useb[i]) szb[++ jsb] = W[i];
        else sznot[++ jsnot] = W[i];
    }
    
    sort(szab + 1, szab + jsab + 1);
    sort(sza + 1, sza + jsa + 1);
    sort(szb + 1, szb + jsb + 1);
    sort(sznot + 1, sznot + jsnot + 1);
    
    Rep(i, 1, jsab) sum1[i] = sum1[i - 1] + szab[i];
    Rep(i, 1, jsa) sum2[i] = sum2[i - 1] + sza[i];
    Rep(i, 1, jsb) sum3[i] = sum3[i - 1] + szb[i];
    
    if(Judge()) {puts("-1"); exit(0) ;}
    
    Rep(i, 1, jsab) Add(szab[i]);
    Rep(i, k + 1, jsa) Add(sza[i]);
    Rep(i, k + 1, jsb) Add(szb[i]);
    Rep(i, 1, jsnot) Add(sznot[i]);    
    
    ato = min(k, jsa);
    bto = min(k, jsb);
    abto = 0;
    
}

bool Judge2(int x) {
    if(k - x > jsa || k - x > jsb || k * 2 - x > m) return 0;
    return 1;
}

void Del(int x) {
    Update();
    Map[x] ++;
    int topbig = Big.top();
    if(x <= topbig) {
        Size --, Sum -= x;
    }
    Update();
}

LL Ask(int x) {
    Update();
    while(Size > x && Big.size()) {
        int topbig = Big.top();
        Size --, Sum -= topbig;
        Big.pop();
        Small.push(topbig);
        Update();
    }
    while(Size < x && Small.size()) {
        int topsmall = Small.top();
        Size ++, Sum += topsmall;
        Small.pop();
        Big.push(topsmall);
        Update();
    }
    return Sum;
}

LL Calc(int x) {
    LL ret = 0;
    while(abto <= x && abto) {
        Del(szab[abto]);
        abto ++;
    }
    ret += sum1[abto - 1];
    while(ato > k - x && ato) {
        Add(sza[ato]);
        ato --;
    }
    ret += sum2[ato];
    while(bto > k - x && bto) {
        Add(szb[bto]);
        bto --;
    }
    ret += sum3[bto];
    ret += Ask(m - k * 2 + x);
    return ret;
}

int main() {
    n = read(), m = read(), k = read();
    Rep(i, 1, n) W[i] = read();
    a = read(); Rep(i, 1, a) W[0] = read(), usea[W[0]] = 1;
    b = read(); Rep(i, 1, b) W[0] = read(), useb[W[0]] = 1;
    
    Now_size = m;
    Bef_work();
    
    abto = 1;
    
    LL Answer = 1e18;
    Rep(i, 0, jsab) {
        if(!Judge2(i)) continue;
        Now_size = m - k * 2 + i;
        Answer = min(Answer, Calc(i));
    }
    cout << (Answer == 1e18 ? -1 : Answer);
    return 0;
}
对顶堆

相关文章: