zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    常用的字符集编码
    live555—VS2010/VS2013 下live555编译、使用及测试(转载)
    win32下Socket编程(转载)
    do{...}while(0)的意义和用法(转载)
    C++ static与单例模式
    MFC多线程各种线程用法 .
    a^1+b problem
    重返现世——题解
    第K大C
    懒癌
  • 原文地址:https://www.cnblogs.com/Onlynagesha/p/8547345.html
Copyright © 2011-2022 走看看