結果

問題 No.855 ヘビの日光浴
コンテスト
ユーザー 梧桐
提出日時 2026-05-19 04:00:34
言語 C++14
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++14 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 176 ms / 3,153 ms
コード長 7,225 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 1,235 ms
コンパイル使用メモリ 122,592 KB
実行使用メモリ 22,272 KB
最終ジャッジ日時 2026-05-19 04:00:44
合計ジャッジ時間 9,202 ms
ジャッジサーバーID
(参考情報)
judge1_0 / judge3_1
純コード判定待ち
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 92
権限があれば一括ダウンロードができます
コンパイルメッセージ
main.cpp: In function 'int main()':
main.cpp:212:15: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17' [-Wc++17-extensions]
  212 |     for (auto [x, y, l_add] : ops) {
      |               ^
main.cpp:220:15: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17' [-Wc++17-extensions]
  220 |     for (auto [k, v] : val_l) { ans += v; }
      |               ^
main.cpp:221:15: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17' [-Wc++17-extensions]
  221 |     for (auto [k, v] : val_r) { ans += v; }
      |               ^
main.cpp:222:15: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17' [-Wc++17-extensions]
  222 |     for (auto [k, v] : val_b) { ans += v; }
      |               ^
main.cpp:223:15: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17' [-Wc++17-extensions]
  223 |     for (auto [k, v] : val_t) { ans += v; }
      |               ^

ソースコード

diff #
raw source code

#include <iostream>
#include <cstdio>
#include <set>
#include <tuple>
#include <unordered_map>
#include <vector>

using namespace std;

typedef long long LL;

const LL INF_EXT = 1LL << 60;
const int INF_KEY = 2000000000;

struct SegTree {
    int n, sz;
    vector<LL> tree;
    vector<int> keys;
    unordered_map<int, int> pos;

    void Init(const vector<int> &sorted_keys) {
        keys = sorted_keys;
        sz = keys.size();
        n = 1;
        while (n < sz) { n *= 2; }
        tree.assign(2 * n, 0);
        pos.clear();
        for (int i = 0; i < sz; ++i) {
            pos[keys[i]] = i;
        }
    }

    void Update(int key, LL value) {
        if (pos.find(key) == pos.end()) return;
        int idx = pos[key] + n;
        tree[idx] = value;
        for (idx /= 2; idx >= 1; idx /= 2) {
            tree[idx] = max(tree[2 * idx], tree[2 * idx + 1]);
        }
    }

    int QueryMin(LL threshold) {
        if (tree[1] < threshold) return INF_KEY;
        int idx = 1;
        while (idx < n) {
            int left = 2 * idx;
            if (tree[left] >= threshold) idx = left;
            else idx = left + 1;
        }
        return keys[idx - n];
    }

    int QueryMaxRec(int idx, int l, int r, LL threshold) {
        if (r - l == 1) return tree[idx] >= threshold ? keys[l] : -1;
        int mid = l + r >> 1;
        int right = 2 * idx + 1, left = 2 * idx;
        if (tree[right] >= threshold) return QueryMaxRec(right, mid, r, threshold);
        if (tree[left] >= threshold) return QueryMaxRec(left, l, mid, threshold);
        return -1;
    }

    int QueryMax(LL threshold) {
        if (tree[1] < threshold) return -1;
        return QueryMaxRec(1, 0, n, threshold);
    }
};

SegTree seg_l, seg_r, seg_b, seg_t;
unordered_map<int, LL> val_l, val_r, val_b, val_t;
int w, h;
LL ans;

LL GetVal(char grp, int key) {
    if (grp == 'L') return val_l.count(key) ? val_l[key] : 0LL;
    if (grp == 'R') return val_r.count(key) ? val_r[key] : 0LL;
    if (grp == 'B') return val_b.count(key) ? val_b[key] : 0LL;
    return val_t.count(key) ? val_t[key] : 0LL;
}

void SetVal(char grp, int key, LL value) {
    if (grp == 'L') {
        val_l[key] = value;
        seg_l.Update(key, value);
    } else if (grp == 'R') {
        val_r[key] = value;
        seg_r.Update(key, value);
    } else if (grp == 'B') {
        val_b[key] = value;
        seg_b.Update(key, value);
    } else {
        val_t[key] = value;
        seg_t.Update(key, value);
    }
}

void ProcessL(int y, LL add) {
    LL cur = GetVal('L', y), new_val = cur + add;
    LL r_val = GetVal('R', y);
    LL cand1 = (w + 1) - r_val;
    int cand2_key = seg_b.QueryMin(y);
    LL cand2 = cand2_key == INF_KEY ? INF_EXT : cand2_key;
    int cand3_key = seg_t.QueryMin((h + 1) - y);
    LL cand3 = cand3_key == INF_KEY ? INF_EXT : cand3_key;
    LL safe_max = min(min(cand1, cand2), cand3) - 1;
    if (new_val <= safe_max) SetVal('L', y, new_val);
    else {
        SetVal('L', y, 0);
        if (cand1 == safe_max + 1) SetVal('R', y, 0);
        if (cand2 == safe_max + 1) SetVal('B', cand2_key, 0);
        if (cand3 == safe_max + 1) SetVal('T', cand3_key, 0);
    }
}

void ProcessR(int y, LL add) {
    LL cur = GetVal('R', y), new_val = cur + add;
    LL l_val = GetVal('L', y);
    LL cand1 = (w + 1) - l_val;
    int bottom_max = seg_b.QueryMax(y);
    LL cand2 = bottom_max == -1 ? INF_EXT : (w + 1) - bottom_max;
    int top_max = seg_t.QueryMax((h + 1) - y);
    LL cand3 = top_max == -1 ? INF_EXT : (w + 1) - top_max;
    LL safe_max = min(min(cand1, cand2), cand3) - 1;
    if (new_val <= safe_max) SetVal('R', y, new_val);
    else {
        SetVal('R', y, 0);
        if (cand1 == safe_max + 1) SetVal('L', y, 0);
        if (cand2 == safe_max + 1) SetVal('B', bottom_max, 0);
        if (cand3 == safe_max + 1) SetVal('T', top_max, 0);
    }
}

void ProcessB(int x, LL add) {
    LL cur = GetVal('B', x), new_val = cur + add;
    LL t_val = GetVal('T', x);
    LL cand1 = (h + 1) - t_val;
    int cand2_key = seg_l.QueryMin(x);
    LL cand2 = cand2_key == INF_KEY ? INF_EXT : cand2_key;
    int cand3_key = seg_r.QueryMin((w + 1) - x);
    LL cand3 = cand3_key == INF_KEY ? INF_EXT : cand3_key;
    LL safe_max = min(min(cand1, cand2), cand3) - 1;
    if (new_val <= safe_max) SetVal('B', x, new_val);
    else {
        SetVal('B', x, 0);
        if (cand1 == safe_max + 1) SetVal('T', x, 0);
        if (cand2 == safe_max + 1) SetVal('L', cand2_key, 0);
        if (cand3 == safe_max + 1) SetVal('R', cand3_key, 0);
    }
}

void ProcessT(int x, LL add) {
    LL cur = GetVal('T', x), new_val = cur + add;
    LL b_val = GetVal('B', x);
    LL cand1 = (h + 1) - b_val;
    int left_max = seg_l.QueryMax(x);
    LL cand2 = left_max == -1 ? INF_EXT : (h + 1) - left_max;
    int right_max = seg_r.QueryMax((w + 1) - x);
    LL cand3 = right_max == -1 ? INF_EXT : (h + 1) - right_max;
    LL safe_max = min(min(cand1, cand2), cand3) - 1;
    if (new_val <= safe_max) SetVal('T', x, new_val);
    else {
        SetVal('T', x, 0);
        if (cand1 == safe_max + 1) SetVal('B', x, 0);
        if (cand2 == safe_max + 1) SetVal('L', left_max, 0);
        if (cand3 == safe_max + 1) SetVal('R', right_max, 0);
    }
}

/**
 * 将边界蛇分四组 (Left/Right/Bottom/Top),各组按 key 建线段树(维护最大延伸值)。
 *
 * 每次操作:new_val = cur + add
 *   safe_max = min(三方向阻挡距离) - 1
 *   若 new_val ≤ safe_max → 更新延伸值;否则 → 撞到的蛇均缩回(置 0)
 *
 * 阻挡查询(以左蛇 (0,y) 为例):
 *   - 对面右蛇 (W+1,y):safe_max < (W+1) - r_val
 *   - 底部蛇 (x,0):QueryMin(延伸值 ≥ y) 返回最小 x(即第一个挡住的列)
 *   - 顶部蛇 (x,H+1):QueryMin(延伸值 ≥ H+1-y) 返回最小 x
 */
int main() {
    int n;
    scanf("%d%d%d", &h, &w, &n);

    vector<tuple<int, int, LL>> ops;
    ops.reserve(n);
    set<int> s_l, s_r, s_b, s_t;
    for (int i = 0, x, y; i < n; ++i) {
        LL l_add;
        scanf("%d%d%lld", &x, &y, &l_add);
        ops.push_back({ x, y, l_add });
        if (x == 0) s_l.insert(y);
        else if (x == w + 1) s_r.insert(y);
        else if (y == 0) s_b.insert(x);
        else s_t.insert(x);
    }

    vector<int> vec_l(s_l.begin(), s_l.end());
    vector<int> vec_r(s_r.begin(), s_r.end());
    vector<int> vec_b(s_b.begin(), s_b.end());
    vector<int> vec_t(s_t.begin(), s_t.end());

    seg_l.Init(vec_l);
    seg_r.Init(vec_r);
    seg_b.Init(vec_b);
    seg_t.Init(vec_t);

    for (int y : vec_l) { val_l[y] = 0; seg_l.Update(y, 0); }
    for (int y : vec_r) { val_r[y] = 0; seg_r.Update(y, 0); }
    for (int x : vec_b) { val_b[x] = 0; seg_b.Update(x, 0); }
    for (int x : vec_t) { val_t[x] = 0; seg_t.Update(x, 0); }

    for (auto [x, y, l_add] : ops) {
        if (x == 0) ProcessL(y, l_add);
        else if (x == w + 1) ProcessR(y, l_add);
        else if (y == 0) ProcessB(x, l_add);
        else ProcessT(x, l_add);
    }

    ans = 0LL;
    for (auto [k, v] : val_l) { ans += v; }
    for (auto [k, v] : val_r) { ans += v; }
    for (auto [k, v] : val_b) { ans += v; }
    for (auto [k, v] : val_t) { ans += v; }
    printf("%lld\n", ans);

    return 0;
}
0