結果

問題 No.945 YKC饅頭
ユーザー btkbtk
提出日時 2019-12-08 00:35:18
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 419 ms / 2,000 ms
コード長 15,892 bytes
コンパイル時間 2,636 ms
コンパイル使用メモリ 222,212 KB
実行使用メモリ 9,392 KB
最終ジャッジ日時 2024-06-08 03:24:40
合計ジャッジ時間 12,501 ms
ジャッジサーバーID
(参考情報)
judge1 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 2 ms
6,940 KB
testcase_02 AC 2 ms
6,944 KB
testcase_03 AC 3 ms
6,940 KB
testcase_04 AC 2 ms
6,940 KB
testcase_05 AC 2 ms
6,940 KB
testcase_06 AC 2 ms
6,944 KB
testcase_07 AC 2 ms
6,940 KB
testcase_08 AC 2 ms
6,940 KB
testcase_09 AC 3 ms
6,944 KB
testcase_10 AC 3 ms
6,940 KB
testcase_11 AC 3 ms
6,944 KB
testcase_12 AC 3 ms
6,940 KB
testcase_13 AC 3 ms
6,940 KB
testcase_14 AC 3 ms
6,940 KB
testcase_15 AC 2 ms
6,940 KB
testcase_16 AC 2 ms
6,944 KB
testcase_17 AC 3 ms
6,940 KB
testcase_18 AC 3 ms
6,940 KB
testcase_19 AC 2 ms
6,944 KB
testcase_20 AC 2 ms
6,940 KB
testcase_21 AC 2 ms
6,940 KB
testcase_22 AC 3 ms
6,940 KB
testcase_23 AC 3 ms
6,940 KB
testcase_24 AC 3 ms
6,940 KB
testcase_25 AC 3 ms
6,944 KB
testcase_26 AC 3 ms
6,940 KB
testcase_27 AC 2 ms
6,944 KB
testcase_28 AC 2 ms
6,940 KB
testcase_29 AC 2 ms
6,940 KB
testcase_30 AC 2 ms
6,940 KB
testcase_31 AC 18 ms
6,940 KB
testcase_32 AC 7 ms
6,944 KB
testcase_33 AC 82 ms
8,324 KB
testcase_34 AC 206 ms
6,944 KB
testcase_35 AC 343 ms
8,128 KB
testcase_36 AC 238 ms
6,944 KB
testcase_37 AC 223 ms
6,940 KB
testcase_38 AC 210 ms
6,944 KB
testcase_39 AC 46 ms
6,940 KB
testcase_40 AC 42 ms
8,020 KB
testcase_41 AC 16 ms
6,948 KB
testcase_42 AC 308 ms
6,944 KB
testcase_43 AC 199 ms
6,944 KB
testcase_44 AC 259 ms
7,672 KB
testcase_45 AC 340 ms
6,944 KB
testcase_46 AC 7 ms
6,944 KB
testcase_47 AC 201 ms
6,944 KB
testcase_48 AC 42 ms
6,940 KB
testcase_49 AC 82 ms
6,944 KB
testcase_50 AC 362 ms
6,940 KB
testcase_51 AC 412 ms
7,896 KB
testcase_52 AC 419 ms
7,660 KB
testcase_53 AC 413 ms
9,368 KB
testcase_54 AC 413 ms
8,012 KB
testcase_55 AC 413 ms
7,880 KB
testcase_56 AC 9 ms
8,020 KB
testcase_57 AC 9 ms
8,516 KB
testcase_58 AC 193 ms
8,428 KB
testcase_59 AC 228 ms
8,480 KB
testcase_60 AC 84 ms
9,024 KB
testcase_61 AC 201 ms
9,392 KB
testcase_62 AC 191 ms
8,300 KB
testcase_63 AC 10 ms
8,164 KB
testcase_64 AC 93 ms
8,036 KB
testcase_65 AC 73 ms
7,928 KB
testcase_66 AC 68 ms
7,560 KB
testcase_67 AC 140 ms
7,804 KB
testcase_68 AC 85 ms
8,112 KB
testcase_69 AC 32 ms
8,380 KB
testcase_70 AC 38 ms
8,104 KB
testcase_71 AC 40 ms
8,972 KB
testcase_72 AC 113 ms
8,044 KB
testcase_73 AC 215 ms
8,636 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

// https://yukicoder.me/problems/no/945
#define CIN_ONLY
#define DECIMAL_DIGITS 10
#define STATIC_MOD 1e9 + 7

#ifdef BTK
/*<head>*/
#    include "Template.hpp"
/*</head>*/
#else
/*<body>*/
/* #region auto includes */
/* #region stl */
/*<stl>*/
#    include <bits/stdc++.h>
#    include <sys/types.h>
#    include <unistd.h>
using namespace std;
/*</stl>*/
/* #endregion */
/* #region template/IncludeSTL.hpp*/
/**
 * @file IncludeSTL.hpp
 * @author btk
 * @brief 標準ライブラリをincludeするだけ
 * @version 0.1
 * @date 2019-07-21
 * @todo 何故か2回includeされる(展開scriptに
 * @copyright Copyright (c) 2019
 *
 */


/* #endregion */
/* #region template/Macro.hpp*/
/**
 * @file Macro.hpp
 * @author btk
 * @brief マクロとか,LLとか
 * @version 0.1
 * @date 2019-07-13
 *
 * @copyright Copyright (c) 2019
 *
 */


//! LL
using LL = long long;

/**
 * @def DEBUG
 * @brief デバッグ用のif文 提出時はif(0)で実行されない
 */

/*</head>*/
#    ifdef BTK
#        define DEBUG if (1)
#    else
#        ifdef CIN_ONLY
#            define FAST_IO
#        endif
#        define DEBUG if (0)
#    endif
/**
 * @def ALL(v)
 * @brief
 * ALLマクロ
 */
#    define ALL(v) (v).begin(), (v).end()

/**
 * @def REC(ret, ...)
 * @brief
 * 再帰ラムダをするためのマクロ
 */
#    define REC(ret, ...) std::function<ret(__VA_ARGS__)>

/**
 * @def VAR_NAME(var)
 * @brief 変数名を取得する
 */
#    define VAR_NAME(var) #    var

/**
 * @brief
 * rangeで生まれる使わない変数を消す用(警告消し)
 */
template <typename T>
inline T &unused_var(T &v) {
    return v;
}
/* #endregion */
/* #region template/IO.hpp*/
/**
 * @file IO.hpp
 * @author btk
 * @brief cin高速化とか,出力の小数桁固定とか
 * @version 0.1
 * @date 2019-07-13
 *
 * @copyright Copyright (c) 2019
 */


/**
 * @brief 入出力の設定を行うための構造体
 */
struct cww {
    /**
     * @brief Construct a new cww::cww object
     * @details
     * CIN_ONLYを定義すると,submit時にcinとscanfの同期を切る設定が走る
     * DECIMAL_DIGITSを定義すると,doubleの出力時指定した桁数分小数部を吐くようになる
     */
    cww() {
#    ifdef FAST_IO
        ios::sync_with_stdio(false);
        cin.tie(0);
#    endif
#    ifdef DECIMAL_DIGITS
        cout << fixed;
        cout << setprecision(DECIMAL_DIGITS);
#    endif
    }
};

//! 入出力設定構造体を実体化
cww star;

/**
 * @brief
 * vectorに直接cin流すためのやつ
 * @tparam T
 * @param is
 * @param v
 * @return istream&
 */
template <typename T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
    for (auto &it : v) is >> it;
    return is;
}
/* #endregion */
/* #region template/Loop.hpp*/
/**
 * @file Loop.hpp
 * @author btk
 * @brief rangeとかループ系のクラス
 * @version 0.1
 * @date 2019-07-13
 *
 * @copyright Copyright (c) 2019
 *
 */


/**
 * @brief
 * rangeを逆向きに操作したいとき用
 * @details
 * ループの範囲は[bg,ed)なので注意
 * @see range
 */
class reverse_range {
  private:
    struct I {
        int x;
        int operator*() { return x - 1; }
        bool operator!=(I &lhs) { return x > lhs.x; }
        void operator++() { --x; }
    };
    I i, n;

  public:
    /**
     * @brief Construct a new reverse range object
     *
     * @param n
     */
    reverse_range(int n) : i({0}), n({n}) {}
    /**
     * @brief Construct a new reverse range object
     *
     * @param i
     * @param n
     */
    reverse_range(int i, int n) : i({i}), n({n}) {}
    /**
     * @brief
     * begin iterator
     * @return I&
     */
    I &begin() { return n; }
    /**
     * @brief
     * end iterator
     * @return I&
     */
    I &end() { return i; }
};
/**
 * @brief
 * python みたいな range-based for を実現
 * @details
 * ループの範囲は[bg,ed)なので注意
 * !つけると逆向きにループが回る (reverse_range)
 * 空間計算量はO(1)
 * 使わない変数ができて警告が出がちなので,unused_varとかを使って警告消しするとよい
 */
class range {
  private:
    struct I {
        int x;
        int operator*() { return x; }
        bool operator!=(I &lhs) { return x < lhs.x; }
        void operator++() { ++x; }
    };
    I i, n;

  public:
    /**
     * @brief Construct a new range object
     *
     * @param n
     */
    range(int n) : i({0}), n({n}) {}
    /**
     * @brief Construct a new range object
     *
     * @param i
     * @param n
     */
    range(int i, int n) : i({i}), n({n}) {}
    /**
     * @brief
     * begin iterator
     * @return I&
     */
    I &begin() { return i; }
    /**
     * @brief
     * end iterator
     * @return I&
     */
    I &end() { return n; }
    /**
     * @brief
     * 逆向きに参照するrange(reverse_rangeを取得できるs)
     * @return reverse_range
     */
    reverse_range operator!() { return reverse_range(*i, *n); }
};
/* #endregion */
/* #region template/MinMaxOperation.hpp*/
/**
 * @file MinMaxOperation.hpp
 * @author btk
 * @brief 最大値とか最小値を求める
 * @version 0.1
 * @date 2019-07-04
 *
 * @copyright Copyright (c) 2019
 *
 */

/**
 * @brief 2項の最小値求める
 *
 * @tparam T
 */
template <typename T>
struct min_op {
    /**
     * @brief 本体
     *
     * @param l
     * @param r
     * @return T
     */
    static T exec(const T l, const T r) { return l < r ? l : r; }
};

/**
 * @brief 2項の最大値求める
 *
 * @tparam T
 */
template <typename T>
struct max_op {
    /**
     * @brief 本体
     *
     * @param l
     * @param r
     * @return T
     */
    static T exec(const T l, const T r) { return l > r ? l : r; }
};

/**
 * @brief テンプレート再帰の末尾
 *
 * @tparam F 二項演算
 * @tparam T
 * @param v
 * @return T
 */
template <typename F, typename T>
inline T multi_op(T &&v) {
    return v;
}

/**
 * @brief 複数項における演算の結果を返す
 *
 * @tparam F
 * @tparam T
 * @tparam Ts
 * @param head
 * @param tail
 * @return T
 */
template <typename F, typename T, typename... Ts>
inline T multi_op(const T head, Ts &&... tail) {
    return F::exec(head, multi_op<F>(tail...));
}

/**
 * @brief 複数項の最小値
 * @see multi_op
 * @tparam T
 * @tparam Ts
 * @param head
 * @param tail
 * @return T
 */
template <typename T, typename... Ts>
inline T multi_min(T &&head, Ts &&... tail) {
    return multi_op<min_op<T>>(head, tail...);
}

/**
 * @brief 複数項の最大値
 * @see multi_op
 * @tparam T
 * @tparam Ts
 * @param head
 * @param tail
 * @return T
 */
template <typename T, typename... Ts>
inline T multi_max(T &&head, Ts &&... tail) {
    return multi_op<max_op<T>>(head, tail...);
}

/**
 * @brief
 * 先頭の値をFで参照する関数に基づいて変更できたらする
 * @tparam F
 * @tparam T
 * @tparam Ts
 * @param target
 * @param candidates
 * @return true
 * @return false
 */
template <typename F, typename T, typename... Ts>
inline bool ch_op(T &target, Ts &&... candidates) {
    const T old = target;
    target      = multi_op<F>(target, candidates...);
    return old != target;
}

/**
 * @brief change min
 * @tparam T 型
 * @param target 変更する値
 * @param candidates
 * @return 更新があればtrue
 */
template <typename T, typename... Ts>
inline bool chmin(T &target, Ts &&... candidates) {
    return ch_op<min_op<T>>(target, candidates...);
}

/**
 * @brief chminのmax版
 * @see chmin
 *  @tparam T 型
 * @param target 変更する値
 * @param candidates
 * @return 更新があればtrue
 */
template <typename T, typename... Ts>
inline bool chmax(T &target, Ts &&... candidates) {
    return ch_op<max_op<T>>(target, candidates...);
}
/* #endregion */
/* #region template/Random.hpp*/
/**
 * @file Random.hpp
 * @author btk
 * @brief 乱数生成系
 * @version 0.1
 * @date 2019-07-13
 * @copyright Copyright (c) 2019
 */


//! 乱数のシード値をプロセスIDとして取得
const pid_t pid = getpid();

/**
 * @brief XorShift32の実装
 */
class XorShift32 {
  private:
    //! XorShiftの現在の値
    unsigned value;

    /**
     * @brief XorShift32のアルゴリズムに基づいて value を更新
     */
    inline void update() {
        value = value ^ (value << 13);
        value = value ^ (value >> 17);
        value = value ^ (value << 5);
    }

    /**
     * @brief 値を更新し,更新前の値を返却
     * @return unsigned 呼び出し時の value を用いる
     */
    inline unsigned get() {
        unsigned v = value;
        update();
        return v;
    }

  public:
    /**
     * @brief [0, 2^bit) の範囲の乱数値を取り出す
     * @tparam デフォルトは31
     * @return int
     */
    template <int bit = 31>
    inline int next_int() {
        return (int)(get() >> (32 - bit));
    }

    /**
     * @brief [-2^bit,2^bit)の範囲の乱数値を取り出す
     * @tparam デフォルトは31
     * @return int
     */
    template <int bit = 31>
    inline int next_signed() {
        unsigned v = get();
        return (int)((v >> (31 - bit)) - (1 << (bit)));
    }

    /**
     * @brief next_int呼び出し時の最大値を取得
     * @tparam 31
     * @return int
     */
    template <int bit = 31>
    inline int range_max() {
        return (int)((1u << bit) - 1);
    };

    /**
     * @brief Construct a new XorShift32 object
     * @param seed
     * @details 初期シードをvalueとするXorShift32のインスタンスを生成
     */
    XorShift32(const unsigned seed) {
        value = seed;
        update();
    }

    /**
     * @brief Construct a new XorShift 32 object
     * @details 初期シードをプロセスIDとするXorShift32のインスタンスを生成
     */
    XorShift32() : XorShift32(pid) {}
};
/* #endregion */
/* #region Template.hpp*/
/**
 * @file Template.hpp
 * @brief 競技プログラミング用テンプレート
 * @author btk15049
 * @date 2019/05/02
 */


/* #endregion */
/* #endregion */
/*</body>*/
#endif


/*
default:: range minimum query
- update(element) : chmin (weak update), set (force update)
- get   (segment) : min(l,r)
*/

constexpr int INF = 1e7;
template <typename SEG>
using SetInitialLeaf = function<void(SEG &, int)>;
template <typename SEG>
using SetInitialSegment = function<void(SEG &, const int, const int)>;
template <typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG &, const int, const int)>;
template <typename RET>
using GetMergedSegment = function<RET(RET, RET)>;
template <typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG &, Q)>;
template <typename SEG>
using LazyUpdate = function<void(SEG &, SEG &, SEG &)>;

struct node {
    int ret;
    bool all;
};


SetInitialLeaf<node> set_leaf = [](node &v, const int id) {
    v.ret = 0;
    v.all = false;
};

SetInitialSegment<node> set_segment = [](node &v, const int l, const int r) {
    v.all = false;
};

GetSingleSegment<int, node> segment_sum = [](node &v, const int l,
                                             const int r) {
    if (v.all) {
        return r - l;
    }
    else {
        return v.ret;
    }
};

GetMergedSegment<int> merge_segment = [](int l, int r) { return l + r; };

UpdateSingleSegment<node, int> update = [](node &v, int l) { v.all = true; };

LazyUpdate<node> lazy = [](node &v, node &l, node &r) {
    l.all |= v.all;
    r.all |= v.all;
};

#ifndef NDBUF
#    define NDBUF
template <typename T>
struct BufferManager {
    T *mem;
    int ptr;
    BufferManager(T *mem) {
        ptr       = 0;
        this->mem = mem;
    }
    T *get(int m) {
        ptr += m;
        return mem + ptr - m;
    }
    void reset() { ptr = 0; }
};

namespace NodeBuffer {
    constexpr int BufferSize = 812345;
    using NodeType           = node;
    NodeType mem[BufferSize];
    BufferManager<NodeType> buffer(mem);
} // namespace NodeBuffer
#endif

template <typename Node, typename RET>
struct SegmentTree {
    int size;
    Node *seg;
    GetSingleSegment<RET, Node> get_single_segment;
    GetMergedSegment<RET> get_merged_segment;
    LazyUpdate<Node> lazy_update;
    void init(int l, int r, SetInitialSegment<Node> &init_segment,
              SetInitialLeaf<Node> &init_leaf, int k = 0) {
        auto &v = seg[k];
        init_segment(v, l, r);
        if (r - l == 1) {
            //葉の時の処理
            init_leaf(v, l);
        }
        else if (r - l > 1) {
            int m = (l + r) / 2;
            init(l, m, init_segment, init_leaf, k * 2 + 1);
            init(m, r, init_segment, init_leaf, k * 2 + 2);
            v.ret =
                get_merged_segment(get_single_segment(seg[k * 2 + 1], l, m),
                                   get_single_segment(seg[k * 2 + 2], m, r));
        }
    }
    SegmentTree(int n, GetSingleSegment<RET, Node> gss,
                GetMergedSegment<RET> gms, SetInitialSegment<Node> sis,
                SetInitialLeaf<Node> sil,
                LazyUpdate<Node> lu      = [](Node &v, Node &l, Node &r) {},
                BufferManager<Node> &buf = NodeBuffer::buffer)
        : get_single_segment(gss), get_merged_segment(gms), lazy_update(lu) {
        size = 1;
        while (size < n) size *= 2;
        seg = buf.get(size * 2 + 10);
        init(0, size, sis, sil);
    }
#define LQ a, b, k * 2 + 1, l, m
#define RQ a, b, k * 2 + 2, m, r
    RET get(int a, int b, int k, int l, int r) {
        if (a <= l && r <= b) return get_single_segment(seg[k], l, r);
        if (r - l > 1) lazy_update(seg[k], seg[2 * k + 1], seg[2 * k + 2]);
        int m   = (l + r) / 2;
        bool ll = !(m <= a || b <= l);
        bool rr = !(r <= a || b <= m);
        RET ret;
        if (ll && rr)
            ret = get_merged_segment(get(LQ), get(RQ));
        else if (ll)
            ret = get(LQ);
        else
            ret = get(RQ);
        seg[k].ret =
            get_merged_segment(get_single_segment(seg[k * 2 + 1], l, m),
                               get_single_segment(seg[k * 2 + 2], m, r));
        return ret;
    }
    RET get(int a, int b) { return get(a, b, 0, 0, size); }
    template <typename Q>
    void update(int a, int b, int k, int l, int r,
                UpdateSingleSegment<Node, Q> &update_segment, Q value) {
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            update_segment(seg[k], value);
        }
        else {
            if (r - l > 1) lazy_update(seg[k], seg[2 * k + 1], seg[2 * k + 2]);
            int m = (l + r) / 2;
            update(LQ, update_segment, value);
            update(RQ, update_segment, value);
            seg[k].ret =
                get_merged_segment(get_single_segment(seg[k * 2 + 1], l, m),
                                   get_single_segment(seg[k * 2 + 2], m, r));
        }
    }
    template <typename Q>
    void update_segment(int a, int b,
                        UpdateSingleSegment<Node, Q> &update_segment, Q value) {
        update(a, b, 0, 0, size, update_segment, value);
    }

    template <typename Q>
    void update_element(int a, UpdateSingleSegment<Node, Q> &update_segment,
                        Q value) {
        update(a, a + 1, 0, 0, size, update_segment, value);
    }
};


int main() {
    /* write here */
    int N, M;
    cin >> N >> M;
    map<string, int> ret;
    SegmentTree<node, int> tree(N + 10, segment_sum, merge_segment, set_segment,
                                set_leaf, lazy);
    for (int i : range(M)) {
        int l, r;
        string s;
        cin >> l >> r >> s;
        l--;
        int add_val = (r - l) - tree.get(l, r);
        ret[s] += add_val;
        //cerr << add_val << endl;
        tree.update_segment(l, r, update, 1);
    }
    cout << ret["Y"] << " ";
    cout << ret["K"] << " ";
    cout << ret["C"] << endl;

    return 0;
}
0