ZOJ 3963

题目大意:

定义“可堆序列”为:可以用该序列的所有元素组成一个小根堆(父子节点的值可以相同),其中父节点在原序列中的位置一定在子节点之前。

给定一个长为N的序列,将它划分成最少的“可堆序列”,并输出任意一种划分方案。

N<=1e5,所有测试点的N之和<=2e6。

利用贪心的思路,假如前K-1个节点已经构成了若干个堆,那么加入第K个节点时,应该在满足条件的前提下,让它的父节点尽可能大,从而给较小的数腾出空间。

如果第K个节点不能加入已有的任何一个堆,就以它为根节点新建一个。(特别地,第一个节点肯定要作为根节点。)

维护时可以用std::set或std::map,注意已有两个孩子的节点要及时删除。

另外要注意“所有测试点的N之和<=2e6”这种限制,测试数据的组数可能会达到百万量级,因此执行memset等初始化操作时一定要控制时间复杂度,memset(arr, b, sizeof(arr))这样的写法是会导致TLE的。

(这点看了别人的代码才意识到,之前还以为是STL常数的问题,然后又是reserve,又是emplace_hint,又是二维数组改一维,一边优化一边还纳闷ZOJ既然开了-O2那么STL不应该这么慢啊……果然是我沙茶了)

(顺便庆祝一下ZOJ支持C++11,撒花ヾ(◍°∇°◍)ノ゙)

代码如下:

#include <cctype>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <forward_list>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <regex>
#include <stdexcept>
#include <string>
#include <tuple>
#include <utility>

#define FILL(arr, ch) memset(arr, ch, sizeof(arr))

using namespace std;

using LL = long long;
template <class Tp>
using MinHeap = priority_queue<Tp, vector<Tp>, greater<Tp>>;
template <class Tp>
using MaxHeap = priority_queue<Tp>;

template <class RAIter>
inline void sortGt(RAIter first, RAIter last) { sort(first, last, greater<decltype(*first)>() ); }

const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const long long inf64 = 0x3f3f3f3f3f3f3f3fLL;

inline bool isEq(double x, double y) { return fabs(x - y) <= eps; }
inline bool isLt(double x, double y) { return y - x > eps; }
inline bool isGt(double x, double y) { return x - y > eps; }

inline int read()
{
    char ch = getchar();
    while (!isdigit(ch))
        ch = getchar();
    int x = ch - '0';
    while (ch = getchar(), isdigit(ch))
    {
        x *= 10;
        x += ch - '0';
    }
    return x;
}

const int maxN = 1e5 + 10;

int A[maxN];
int N;

void input()
{
    N = read();
    for (int* it = A + 1; it <= A + N; ++it)
        *it = read();
}

const int noChild = -1;

vector<int> nodes;
int ch0[maxN], ch1[maxN];
bool vis[maxN];

void init()
{
    memset(ch0, -1, sizeof(int) * (N + 1));
    memset(ch1, -1, sizeof(int) * (N + 1));
    memset(vis, 0, sizeof(bool) * (N + 1));
}

inline bool addChild(int f, int c)
{
    if (ch0[f] == noChild)
    {
        ch0[f] = c;
        return false;
    }
    else
    {
        ch1[f] = c;
        return true;
    }
}

void printHeap(int headId)
{
    nodes.clear();
    nodes.push_back(headId);

    for (size_t i = 0; i < nodes.size(); ++i)
    {
        int cur = nodes[i];
        vis[cur] = true;
        if (ch0[cur] != noChild)
        {
            nodes.push_back(ch0[cur]);
            if (ch1[cur] != noChild)
                nodes.push_back(ch1[cur]);
        }
    }

    printf("%zu", nodes.size());
    sort(nodes.begin(), nodes.end());
    for (int v: nodes)
        printf(" %d", v);
    putchar('
');
}

void solve()
{
    multimap<int, int, greater<int>> nodeSet;
    int heapN = 0;

    init();
    for (int i = 1; i <= N; i++)
    {
        auto iter = nodeSet.lower_bound(A[i]);
        if (iter == nodeSet.end())
        {
            heapN += 1;
            nodeSet.emplace_hint(iter, A[i], i);
        }
        else if (addChild(iter->second, i))
        {
            nodeSet.erase(iter);
            nodeSet.emplace(A[i], i);
        }
        else
            nodeSet.emplace_hint(iter, A[i], i);
    }

    printf("%d
", heapN);
    for (int i = 1; i <= N; i++)
        if (!vis[i])
            printHeap(i);
}

//#include <boost/progress.hpp>

int main()
{
    //boost::progress_timer timer(cerr);
    int T;
    scanf("%d", &T);
    nodes.reserve(maxN);
    while (T--)
    {
        input();
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Onlynagesha/p/8547345.html