根据霍夫曼树的构建方法,我们容易想到,把看作一个三元组,分别表示当前根的值,树高,等价类个数

我们有一个贪心的做法,在val相同时,选择两个最小的dep树合并,如果就是自己和自己合并,如果是奇数个则拆出来单独一个

用优先队列维护,时间复杂度:

还不能通过此题

继续观察性质,发现三元组的val递增,于是我们就可以使用同[NOIP2016 提高组] 蚯蚓同样的思路

开两个queue维护就消去了优先队列的log

时间复杂度:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fr first
#define sc second
using i64 = long long;
inline int rd(void) {
    int s = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')
            f = 0;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        s = s * 10 + c - '0';
        c = getchar();
    }
    return f ? s : -s;
}
const int N = 1e5 + 10;
struct node {
    int val, dep, num;
    inline bool operator<(const node &o) const {
        if (val != o.val)
            return val < o.val;
        return dep < o.dep;
    }
    inline node operator+(const node &o) const {
        return (node){val + o.val, max(dep, o.dep) + 1, 1};
    }
};

int n, b[N];
node ans;

bool posi;

struct Heap {
    deque<node> q[2];

    bool empty() { return q[0].empty() && q[1].empty(); }

    node top() {
        if (q[0].empty() | q[1].empty())
            return q[posi = q[0].empty()].front();
        return q[0].front() < q[1].front() ? (posi = 0, q[0].front())
                                           : (posi = 1, q[1].front());
    }
} heap;

signed main() {
    n = rd();
    for (int i = 1; i <= n; i++) {
        b[i] = rd();
        if (b[i])
            heap.q[0].push_back({i, 0, b[i]});
    }
    while (!heap.empty()) {
        node k = heap.top();
        heap.q[posi].pop_front();
        if (k.num == 1) {
            if (heap.empty()) {
                cout << k.dep << endl;
                break;
            }
            node k2 = heap.top();
            heap.q[posi].pop_front();
            k2.num--;
            if (k2.num)
                heap.q[posi].push_front(k2);
            heap.q[1].push_back(k + k2);
            continue;
        }
        if (k.num & 1) {
            heap.q[posi].push_front({k.val, k.dep, 1});
        }
        heap.q[1].push_back({k.val * 2, k.dep + 1, k.num / 2});
    }
    return 0;
}