スカット - 131 - ゲームIIをプレイするPが小さい - 貪欲 - バランスの取れた木

https://scut.online/p/131

人の厳選グループがモンスターを再生する場合、最初に、あなたがメインの最大のBプレイを投げたのタスク、それほど悪くないを置くことができます。そして、このbが最大の、他の人がスパーリングを列挙考えます。AI + k個の*のBI + SUMC-CI始まり、これはよく理解され、その人しかプレイするものを選ぶことができスパーリンググループ、一人一人をスパーリングの規定以来、グループを戦うために最もトン= K-1のGeモンスターで分離されています、それは確かに貪欲な選択VJ = AJ + T BJ-CJ最大の個々の遊びです。それは、それを維持するためにTreap(カジュアル、しかし、髪WAの多くを)置きます。

このテンプレートは、私が実際にしても、草を初期化し、独自のを書いていないことに注意してください。しかしTreap具体的な原理は非常に明確ではありません。

WAは、k個のポイントを超えていないことに注意してくださいは、個人を見つけるために、vは杭と両性愛よりも大きくなります。右部分木が空になると、あなたが終了することができますという意味ではありませんか、今第二の分類が入っているとき、それはここサブツリー可能で便利です。

誰かが直接二分法を探してください、心が千頭のの泥の馬です。さて、あなたはバランスの取れたツリーを学ぶとき。

二回が挿入されているので、ダブルスペースを開くには注意してください。あなたは回復のホールドを取得しない限り?、省略測定された空間の少しを行うには順調に回復。これができるように、n個の点の最大値が直接直感的に同時に存在しているので:STLstack(?そうでない場合は、あなたの顔を無駄にしないの配列を使用することはできません)Newnode内部スタックから削除する場合、内部スタックする時間に戻ってIDを削除し、前方に置きます。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 200000;

int ch[MAXN + 5][2];
int val[MAXN + 5], dat[MAXN + 5];
int siz[MAXN + 5], cnt[MAXN + 5];
ll sum[MAXN + 5];
int tot, root;

inline void Init() {
    tot = 0;
    root = 0;
}

inline int NewNode(int v) {
    ch[++tot][0] = 0;
    ch[tot][1] = 0;
    val[tot] = v, dat[tot] = rand();
    siz[tot] = 1, cnt[tot] = 1;
    sum[tot] = v;
    return tot;
}

inline void PushUp(int id) {
    siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
    sum[id] = sum[ch[id][0]] + sum[ch[id][1]] + 1ll * val[id] * cnt[id];
}

inline void Rotate(int &id, int d) {
    int temp = ch[id][d ^ 1];
    ch[id][d ^ 1] = ch[temp][d];
    ch[temp][d] = id;
    id = temp;
    PushUp(ch[id][d]), PushUp(id);
}

inline void Insert(int &id, int v) {
    if(!id)
        id = NewNode(v);
    else {
        if(v == val[id])
            ++cnt[id];
        else {
            int d = v < val[id] ? 0 : 1;
            Insert(ch[id][d], v);
            if(dat[id] < dat[ch[id][d]])
                Rotate(id, d ^ 1);
        }
        PushUp(id);
    }
}

void Remove(int &id, int v) {
    if(!id)
        return;
    else {
        if(v == val[id]) {
            if(cnt[id] > 1) {
                cnt[id]--;
                PushUp(id);
            } else if(ch[id][0] || ch[id][1]) {
                if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]])
                    Rotate(id, 1), Remove(ch[id][1], v);
                else
                    Rotate(id, 0), Remove(ch[id][0], v);
                PushUp(id);
            } else
                id = 0;
        } else {
            v < val[id] ? Remove(ch[id][0], v) : Remove(ch[id][1], v);
            PushUp(id);
        }
    }
}

ll GetSum(int bi, int k) {
    if(k == 0)
        return 0;
    //把大于bi的最大的至多k个v全部加起来,每加一个减去一个bi
    int r = root;
    ll res = 0;
    while(r) {
        if(bi >= val[r] || (ch[r][1] && siz[ch[r][1]] >= k)) {
            //bi不比这个节点小,这个节点没用,向右走
            //或者前k大完全在右子树中
            r = ch[r][1];
            continue;
        } else {
            //有用的完全在该节点及其右子树中
            /*if(!ch[r][1])
                return res;*/
            res += sum[ch[r][1]];
            res -= 1ll * siz[ch[r][1]] * bi;
            k -= siz[ch[r][1]];
            if(k <= cnt[r]) {
                res += 1ll * k * (val[r] - bi);
                k = 0;
                return res;
            }
            else{
                res += 1ll * cnt[r] * (val[r] - bi);
                k -=cnt[r];
            }
            r=ch[r][0];
        }
    }
    return res;
}

int n, k;
struct Char {
    int a, b, c;
    int v;
    Char() {};
    Char(int _a, int _b, int _c) {
        a = _a;
        b = _b;
        c = _c;
        v = a + b - c;
    }
} cha[100005];

ll sumC;

ll calc(int id) {
    ll M = sumC - cha[id].c + cha[id].a + 1ll * k * cha[id].b  ;
    Remove(root, cha[id].v);
    //至多从平衡树拿走k-1个
    ll res = GetSum(cha[id].b, k - 1);
    Insert(root, cha[id].v);
    return M + res;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &k);
        sumC = 0;
        Init();
        for(int i = 1; i <= n; ++i) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            cha[i] = Char(a, b, c);
            sumC += c;
            Insert(root, cha[i].v);
        }
        ll ans = 0;
        for(int i = 1; i <= n; ++i)
            ans = max(ans, calc(i));
        printf("%lld\n", ans);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/Yinku/p/11324839.html
おすすめ