1. 程式人生 > 實用技巧 >[CF1398E] Two Types of Spells - 貪心,堆

[CF1398E] Two Types of Spells - 貪心,堆

Description

動態維護一個技能集合,技能分為兩種,普通技能和超級技能。所有技能會被按照一個排列執行,如果技能 \(i\) 被執行時它的前一個技能是普通技能,那麼會產生 \(w_i\) 的貢獻;如果是超級技能則會產生 \(2w_i\) 的貢獻。每次新增或刪除技能後,求當前技能集合的最大貢獻。

Solution

考慮維護三個技能集合:setNormal 表示普通技能集合,setHigh 表示當前所有技能中,貢獻較高的技能的集合,setLowsetHigh 的補集。

在任意時刻,我們控制 setHigh 的大小為當前超級技能的總個數,那麼 sum(*)+sum(setHigh) 基本就是答案,但需要做一點修正。

考慮如果我們希望將所有的超級技能翻倍,但這時一定有一個超級技能是不能被翻倍的(顯然我們會選擇最小的那一個)。

考慮如果我們希望翻倍的技能中有一個不是超級技能,那麼這時這些技能被同時翻倍是可以滿足的。

因此,我們從上面的近似答案中,減去當前 setHigh 集合的最小值,再加上當前 setNormal 集合的最大值,就是答案。

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

#define int long long
const int N = 1000005;

#define dbg(y, x) ;

int n, countMagic, ans;
set<int> setHigh, setLow, setNormal;

signed main()
{
    ios::sync_with_stdio(false);

    cin >> n;
    while (n--)
    {
        int type, value;
        cin >> type >> value;
        ans += value;
        if (value > 0)
        {
            if (type == 0)
                setNormal.insert(value);
            if (type == 1)
                countMagic++;
            if (setHigh.size() && value >= *setHigh.begin())
                setHigh.insert(value), ans += value;
            else
                setLow.insert(value);
        }
        else
        {
            value *= -1;
            if (type == 0)
                setNormal.erase(value);
            if (type == 1)
                countMagic--;
            if (setLow.find(value) != setLow.end())
                setLow.erase(value);
            else
                setHigh.erase(value), ans -= value;
        }
        while (setHigh.size() > countMagic)
        {
            ans -= *setHigh.begin();
            setLow.insert(*setHigh.begin());
            setHigh.erase(*setHigh.begin());
        }
        while (setHigh.size() < countMagic)
        {
            ans += *setLow.rbegin();
            setHigh.insert(*setLow.rbegin());
            setLow.erase(*setLow.rbegin());
        }
        int tans = ans;
        if (setHigh.size())
        {
            tans -= *setHigh.begin();
            if (setNormal.size())
                tans += *setNormal.rbegin();
            if (tans > ans)
                tans = ans;
        }
        cout << tans << endl;
        dbg("lowSize", setLow.size());
        dbg("highSize", setHigh.size());
    }
}