結果
問題 | No.2404 Vertical Throw Up |
ユーザー | marc2825 |
提出日時 | 2023-08-22 05:42:15 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 108 ms / 2,000 ms |
コード長 | 10,106 bytes |
コンパイル時間 | 1,092 ms |
コンパイル使用メモリ | 111,500 KB |
実行使用メモリ | 6,944 KB |
最終ジャッジ日時 | 2024-05-09 11:38:32 |
合計ジャッジ時間 | 3,540 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,940 KB |
testcase_02 | AC | 2 ms
6,940 KB |
testcase_03 | AC | 86 ms
6,940 KB |
testcase_04 | AC | 73 ms
6,940 KB |
testcase_05 | AC | 108 ms
6,940 KB |
testcase_06 | AC | 2 ms
6,940 KB |
testcase_07 | AC | 108 ms
6,940 KB |
testcase_08 | AC | 83 ms
6,940 KB |
testcase_09 | AC | 69 ms
6,940 KB |
testcase_10 | AC | 20 ms
6,944 KB |
testcase_11 | AC | 19 ms
6,940 KB |
testcase_12 | AC | 13 ms
6,944 KB |
testcase_13 | AC | 2 ms
6,940 KB |
testcase_14 | AC | 3 ms
6,944 KB |
testcase_15 | AC | 3 ms
6,940 KB |
testcase_16 | AC | 3 ms
6,944 KB |
testcase_17 | AC | 3 ms
6,944 KB |
testcase_18 | AC | 3 ms
6,940 KB |
testcase_19 | AC | 3 ms
6,940 KB |
testcase_20 | AC | 3 ms
6,940 KB |
testcase_21 | AC | 3 ms
6,940 KB |
testcase_22 | AC | 2 ms
6,944 KB |
testcase_23 | AC | 2 ms
6,944 KB |
testcase_24 | AC | 3 ms
6,940 KB |
testcase_25 | AC | 2 ms
6,944 KB |
testcase_26 | AC | 2 ms
6,944 KB |
testcase_27 | AC | 3 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,944 KB |
testcase_31 | AC | 3 ms
6,940 KB |
testcase_32 | AC | 2 ms
6,940 KB |
コンパイルメッセージ
main.cpp:73: warning: "debug" redefined 73 | #define debug(...) void(0) | main.cpp:68: note: this is the location of the previous definition 68 | #define debug(x) void(0) |
ソースコード
#include <iostream> #include <iomanip> #include <cassert> #include <limits> #include <vector> #include <set> #include <deque> #include <cmath> #include <algorithm> using namespace std; using ll = long long; using ld = long double; using vll = vector<ll>; using vvll = vector<vll>; using vvvll = vector<vvll>; using vi = vector<int>; using vvi = vector<vi>; using vvvi = vector<vvi>; using vld = vector<ld>; using vd = vector<double>; using vvd = vector<vd>; using vc = vector<char>; using vvc = vector<vc>; using vs = vector<string>; using vb = vector<bool>; using vvb = vector<vb>; using pii = pair<int, int>; using pcc = pair<char, char>; using pll = pair<ll, ll>; using pdd = pair<double, double>; using pldld = pair<ld,ld>; using vpii = vector<pii>; using vpll = vector<pll>; template<class T>bool chmax(T& a, const T& b) { if (a < b) { a = b; return 1; } return 0; } template<class T>bool chmin(T& a, const T& b) { if (b < a) { a = b; return 1; } return 0; } #define rep(i, n) for (ll i = 0; i < ll(n); i++) #define repback(i, n) for (ll i = n-1; i >= 0; i--) #define REP(i, a, b) for (ll i = a; i < ll(b); i++) #define REPBACK(i, a, b) for (ll i = a-1; i >= ll(b); i--) #define all(x) (x).begin(), (x).end() #define UNIQUE(A) A.erase(unique(all(A)), A.end()) // sortしてから使う #define include(y, x, H, W) (0 <= x && x < W && 0 <= y && y < H) #define square(x) (x) * (x) #define pb push_back #define eb emplace_back #define EPS (1e-10) #define equals(a,b) (fabs((a) - (b)) < EPS) #ifndef ONLINE_JUDGE #define debug1(x) cout << "debug:" << (x) << endl #define debug2(x, y) cout << "debug:" << (x) << " " << (y) << endl #define debug3(x, y, z) cout << "debug:" << (x) << " " << (y) << " " << (z) << endl #define debug4(x, y, z, w) cout << "debug:" << (x) << " " << (y) << " " << (z) << " " << (w) << endl #define debug5(x, y, z, w, v) cout << "debug:" << (x) << " " << (y) << " " << (z) << " " << (w) << " " << (v) << endl #define overload5(a, b, c, d, e, f, ...) f #define debug(...) overload5(__VA_ARGS__, debug5, debug4, debug3, debug2, debug1)(__VA_ARGS__) #define debug2C(x, y) cout << "debug:" << (x) << " : " << (y) << endl #define debug3P(x, y, z) cout << "debug:" << (x) << ", " << (y) << " : " << (z) << endl #define debug3C(x, y, z) cout << "debug:" << (x) << " : " << (y) << ", " << (z) << endl #define debuga cerr << "a" << endl #else #define debug(x) void(0) #define debug2(x, y) void(0) #define debug3(x, y, z) void(0) #define debug4(x, y, z, w) void(0) #define debug5(x, y, z, w, v) void(0) #define debug(...) void(0) #define debug2C(x, y) void(0) #define debug3P(x, y, z) void(0) #define debug3C(x, y, z) void(0) #define debuga void(0) #define TIMER_START void(0) #define TIMER_END void(0) #define TIMECHECK void(0) #endif const long long INFL = 1000000000000000000ll; const long long INFLMAX = numeric_limits< long long >::max(); // 9223372036854775807 const int INF = 1000000000; const int INFMAX = numeric_limits< int >::max(); // 2147483647 const int mod1 = 1000000007; const int mod2 = 998244353; const vi dx1 = {1,0,-1,0}; const vi dy1 = {0,1,0,-1}; const vi dx2 = {0, 1, 1, 1, 0, -1, -1, -1, 0}; const vi dy2 = {1, 1, 0, -1, -1, -1, 0, 1, 1}; const char nl = '\n'; // vector出力 template<typename T> ostream& operator << (ostream& os, vector<T>& vec) { os << "["; for (int i = 0; i<vec.size(); i++) { os << vec[i] << (i + 1 == vec.size() ? "" : ", "); } os << "]"; return os; } // pair出力 template<typename T, typename U> ostream& operator << (ostream& os, pair<T, U>& pair_var) { os << "(" << pair_var.first << ", " << pair_var.second << ")"; return os; } // ############################ // # # // # C O D E S T A R T # // # # // ############################ /// 直線 y = kx+m, p は不要な直線か?の判定 / クエリ処理における二分探索 に用いる値 (具体的には、傾き降順で次の直線との交点のx座標 = (y切片の差) / (傾きの差) ) template <typename T = long long> struct Line { mutable T k, m, p; bool operator<(const Line& o) const { return k < o.k; } bool operator<(T x) const { return p < x; } T get_value(T x) const { return k * x + m; } }; /// div(a,b) = (for doubles, use inf = 1/.0, div(a,b) = a/b) template <typename T = long long> T lc_inf() { return numeric_limits<T>::max(); } template <> long double lc_inf<long double>() { return 1 / .0; } template <typename T = long long> T lc_div(T a, T b) { // クエリが整数ならfloored division でよい, considered negative return a / b - (((a ^ b) < 0) && (a % b)); } template <> long double lc_div(long double a, long double b) { return a / b; } template <> double lc_div(double a, double b) { return a / b; } /// Convex Hull Trick // 直線群 kx+m を管理(追加可能)、任意のxでの最大値/最小値取得クエリをそれぞれ O(log N) で処理可能 (N = 直線の数) // Minimize でクエリの種類(最小/最大取得)を指定、MonotonicAdd で 追加する直線の傾きの単調性(max->降順/min->昇順)が保証されているか(単調なら線形時間に出来る)を指定 // 何をしてるかは Reference[3] がわかりやすい(グラフをイメージすると更によい) template <typename T, bool Minimize = true, bool MonotonicAdd = false> class ConvexHullTrick : multiset<Line<T>, less<> > { private: using base = multiset<Line<T>, less<> >; using base::begin, base::end, base::insert, base::erase, base::rbegin, base::rend; using base::empty, base::lower_bound; const T inf = lc_inf<T>(); deque<Line<T> > deq; /// 直線bが不要かどうかを判定(要するに直線bが凸包を構成しているかを判定しており、これで交点pのx座標の単調性が保たれる) bool noneed(const Line<T> &a, const Line<T> &b, const Line<T> &c) { // TODO : オーバーフロー関連 if((c.k != b.k && abs(b.m - a.m) >= inf / abs(c.k - b.k)) || (c.m != b.m && abs(b.k - a.k) >= inf / abs(c.m - b.m))) return lc_div(b.m - a.m, a.k - b.k) >= lc_div(c.m - b.m, b.k - c.k); else return ((b.m - a.m) * (c.k - b.k)) >= ((b.k - a.k) * (c.m - b.m)); } /// 直線a,bとの交点のx座標(a->p)を計算してから、直線bが不要かどうかを判定 bool calc_intersect_noneed(typename base::iterator a, typename base::iterator b) { if (b == end()) { a->p = inf; return false; } if (a->k == b->k) a->p = (a->m > b->m ? inf : -inf); else a->p = lc_div(b->m - a->m, a->k - b->k); return a->p >= b->p; } /// multiset -> deque に格納(単調クエリ用) void build_deque() { assert(!empty()); auto it = rbegin(); while(it != rend()) { deq.push_back(*it); it++; } } public: /// 直線 kx+m を追加(同時に不要な直線たちは削除される) void add(T k, T m) { if (Minimize) k = -k, m = -m; if(!MonotonicAdd) { auto cur = insert({k, m, 0}); auto nxt = cur; nxt++; while (calc_intersect_noneed(cur, nxt)) nxt = erase(nxt); auto prev = cur; if (prev != begin() && calc_intersect_noneed(--prev, cur)) { cur = erase(cur); calc_intersect_noneed(prev, cur); } while ((cur = prev) != begin() && (--prev)->p >= cur->p) calc_intersect_noneed(prev, erase(cur)); } else { Line<T> l = {k, m, 0}; int sz = deq.size(); while ((sz = deq.size()) >= 2 && noneed(deq[sz-2], deq[sz-1], l)) deq.pop_back(); deq.push_back(l); } } /// 直線群の x における 最小値/最大値 を取得 // O(log N) T query(T x) { T value; if (!MonotonicAdd) { assert(!empty()); auto l = *lower_bound(x); value = l.get_value(x); } else { assert(!deq.empty()); int ng = -1, ok = (int)deq.size() - 1; while(ok - ng > 1) { int mid = (ok + ng) / 2; if(deq[mid].get_value(x) <= deq[mid + 1].get_value(x)) ng = mid; else ok = mid; } value = deq[ok].get_value(x); } return (Minimize ? -value : value); } /// xが(max->降順、min->昇順) という条件で、直線群の x における 最小値/最大値 を取得 // O(N) 、破壊的操作 T query_monotonic(T x) { if(!MonotonicAdd && deq.empty()) build_deque(); assert(!deq.empty()); T value = deq.front().get_value(x); while (deq.size() >= 2 && (value <= (deq[1].get_value(x)))) { deq.pop_front(); value = deq.front().get_value(x); } return (Minimize ? -value : value); } }; template <typename T> using CHT_min = ConvexHullTrick<T, true, false>; template <typename T> using CHT_min_monotonicadd = ConvexHullTrick<T, true, true>; template <typename T> using CHT_max = ConvexHullTrick<T, false, false>; template <typename T> using CHT_max_monotonicadd = ConvexHullTrick<T, false, true>; int main() { // cin.tie(0); // ios_base::sync_with_stdio(false); // cout << fixed << setprecision(15); ll a; cin >> a; CHT_max<ll> CHT; int Q; cin >> Q; while(Q--) { int q; cin >> q; if(q == 1) { ll s,t; cin >> s >> t; CHT.add(a*(s+t), -a*s*t); } else { ll t; cin >> t; cout << max(0ll, -a*t*t + CHT.query(t)) << nl; } } }