제출 #672643

#제출 시각아이디문제언어결과실행 시간메모리
672643ForestedI want to be the very best too! (NOI17_pokemonmaster)C++17
35 / 100
758 ms71132 KiB
#ifndef LOCAL
#define FAST_IO
#endif

// ============
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#define OVERRIDE(a, b, c, d, ...) d
#define REP2(i, n) for (i32 i = 0; i < (i32) (n); ++i)
#define REP3(i, m, n) for (i32 i = (i32) (m); i < (i32) (n); ++i)
#define REP(...) OVERRIDE(__VA_ARGS__, REP3, REP2)(__VA_ARGS__)
#define PER(i, n) for (i32 i = (i32) (n) - 1; i >= 0; --i)
#define ALL(x) begin(x), end(x)

using namespace std;

using u32 = unsigned int;
using u64 = unsigned long long;
using u128 = __uint128_t;
using i32 = signed int;
using i64 = signed long long;
using i128 = __int128_t;
using f64 = double;
using f80 = long double;

template <typename T>
using Vec = vector<T>;

template <typename T>
bool chmin(T &x, const T &y) {
    if (x > y) {
        x = y;
        return true;
    }
    return false;
}
template <typename T>
bool chmax(T &x, const T &y) {
    if (x < y) {
        x = y;
        return true;
    }
    return false;
}

istream &operator>>(istream &is, i128 &x) {
    i64 v;
    is >> v;
    x = v;
    return is;
}
ostream &operator<<(ostream &os, i128 x) {
    os << (i64) x;
    return os;
}
istream &operator>>(istream &is, u128 &x) {
    u64 v;
    is >> v;
    x = v;
    return is;
}
ostream &operator<<(ostream &os, u128 x) {
    os << (u64) x;
    return os;
}

[[maybe_unused]] constexpr i32 INF = 1000000100;
[[maybe_unused]] constexpr i64 INF64 = 3000000000000000100;
struct SetUpIO {
    SetUpIO() {
#ifdef FAST_IO
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
#endif
        cout << fixed << setprecision(15);
    }
} set_up_io;
// ============

#ifdef DEBUGF
#else
#define DBG(x) (void)0
#endif

// ============

#include <limits>
#include <utility>

template <typename T>
struct Add {
    using Value = T;
    static Value id() {
        return T(0);
    }
    static Value op(const Value &lhs, const Value &rhs) {
        return lhs + rhs;
    }
    static Value inv(const Value &x) {
        return -x;
    }
};

template <typename T>
struct Mul {
    using Value = T;
    static Value id() {
        return Value(1);
    }
    static Value op(const Value &lhs, const Value &rhs) {
        return lhs * rhs;
    }
    static Value inv(const Value &x) {
        return Value(1) / x;
    }
};

template <typename T>
struct Min {
    using Value = T;
    static Value id() {
        return std::numeric_limits<T>::max();
    }
    static Value op(const Value &lhs, const Value &rhs) {
        return std::min(lhs, rhs);
    }
};

template <typename T>
struct Max {
    using Value = T;
    static Value id() {
        return std::numeric_limits<Value>::min();
    }
    static Value op(const Value &lhs, const Value &rhs) {
        return std::max(lhs, rhs);
    }
};

template <typename T>
struct Xor {
    using Value = T;
    static Value id() {
        return T(0);
    }
    static Value op(const Value &lhs, const Value &rhs) {
        return lhs ^ rhs;
    }
    static Value inv(const Value &x) {
        return x;
    }
};

template <typename Monoid>
struct Reversible {
    using Value = std::pair<typename Monoid::Value, typename Monoid::Value>;
    static Value id() {
        return Value(Monoid::id(), Monoid::id());
    }
    static Value op(const Value &v1, const Value &v2) {
        return Value(
            Monoid::op(v1.first, v2.first),
            Monoid::op(v2.second, v1.second));
    }
};

// ============
// ============

#include <cassert>

template <typename Monoid>
class SparseSegmentTree {
public:
    using Value = typename Monoid::Value;
    using Index = long long;
    
private:
    struct Node {
        Node *lft;
        Node *rgt;
        Value prod;
        
        Node(Value v) : lft(nullptr), rgt(nullptr), prod(v) {}
        
#ifdef LOCAL
        ~Node() {
            if (lft) {
                delete lft;
            }
            if (rgt) {
                delete rgt;
            }
        }
#endif
        
        void update_prod() {
            if (!lft && !rgt) {
                prod = Monoid::id();
            } else if (!lft) {
                prod = rgt->prod;
            } else if (!rgt) {
                prod = lft->prod;
            } else {
                prod = Monoid::op(lft->prod, rgt->prod);
            }
        }
    };
    
    static Node *update(Node *cur, Index curl, Index curr, Index upd, Value v) {
        if (!cur) {
            cur = new Node(Monoid::id());
        }
        if (curr - curl == 1) {
            cur->prod = v;
        } else {
            Index curm = (curl + curr) / 2;
            if (upd < curm) {
                cur->lft = update(cur->lft, curl, curm, upd, v);
            } else {
                cur->rgt = update(cur->rgt, curm, curr, upd, v);
            }
            cur->update_prod();
        }
        return cur;
    }
    
    static Value prod(Node *cur, Index curl, Index curr, Index qryl, Index qryr) {
        if (!cur || curr <= qryl || qryr <= curl) {
            return Monoid::id();
        }
        if (qryl <= curl && curr <= qryr) {
            return cur->prod;
        }
        Index curm = (curl + curr) / 2;
        Value pl = prod(cur->lft, curl, curm, qryl, qryr);
        Value pr = prod(cur->rgt, curm, curr, qryl, qryr);
        return Monoid::op(pl, pr);
    }
    
    Index lft;
    Index rgt;
    Node *root;
    
public:
    SparseSegmentTree() : lft(0), rgt(1), root(nullptr) {}
    SparseSegmentTree(Index n) : lft(0), rgt(n), root(nullptr) {
        assert(n > 0);
    }
    SparseSegmentTree(Index l, Index r) : lft(l), rgt(r), root(nullptr) {
        assert(l < r);
    }
    
    void update(Index idx, Value v) {
        root = update(root, lft, rgt, idx, v);
    }
    
    Value prod(Index l, Index r) const {
        return prod(root, lft, rgt, l, r);
    }
};
// ============
// ============

#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>

class HeavyLightDecomposition {
    std::vector<int> siz;
    std::vector<int> par;
    std::vector<int> hea;
    std::vector<int> in;
    std::vector<int> out;
    std::vector<int> dep;
    std::vector<int> rev;

    template <typename G>
    void dfs1(G &g, int v) {
        if (!g[v].empty() && (int) g[v][0] == par[v]) {
            std::swap(g[v][0], g[v].back());
        }
        for (auto &e : g[v]) {
            int u = (int)e;
            if (u != par[v]) {
                par[u] = v;
                dfs1(g, u);
                siz[v] += siz[u];
                if (siz[u] > siz[(int) g[v][0]]) {
                    std::swap(g[v][0], e);
                }
            }
        }
    }

    template <typename G>
    void dfs2(const G &g, int v, int &time) {
        in[v] = time;
        rev[time++] = v;
        for (auto &e : g[v]) {
            int u = (int)e;
            if (u == par[v]) {
                continue;
            }
            if (u == (int) g[v][0]) {
                hea[u] = hea[v];
            } else {
                hea[u] = u;
            }
            dep[u] = dep[v] + 1;
            dfs2(g, u, time);
        }
        out[v] = time;
    }

public:
    template <typename G>
    HeavyLightDecomposition(G &g, int root = 0) :
        siz(g.size(), 1),
        par(g.size(), root),
        hea(g.size(), root),
        in(g.size(), 0),
        out(g.size(), 0),
        dep(g.size(), 0),
        rev(g.size(), 0) {
        assert(root >= 0 && root < (int) g.size());
        dfs1(g, root);
        int time = 0;
        dfs2(g, root, time);
    }

    int subtree_size(int v) const {
        assert(v >= 0 && v < (int) siz.size());
        return siz[v];
    }

    int parent(int v) const {
        assert(v >= 0 && v < (int) par.size());
        return par[v];
    }

    int in_time(int v) const {
        assert(v >= 0 && v < (int) in.size());
        return in[v];
    }

    int out_time(int v) const {
        assert(v >= 0 && v < (int) out.size());
        return out[v];
    }

    int depth(int v) const {
        assert(v >= 0 && v < (int) dep.size());
        return dep[v];
    }

    int time_to_vertex(int t) const {
        assert(t >= 0 && t < (int) rev.size());
        return rev[t];
    }
    
    int la(int v, int k) const {
        assert(v >= 0 && v < (int) dep.size());
        assert(k >= 0);
        if (k > dep[v]) {
            return -1;
        }
        while (true) {
            int u = hea[v];
            if (in[u] + k <= in[v]) {
                return rev[in[v] - k];
            }
            k -= in[v] - in[u] + 1;
            v = par[u];
        }
        return 0;
    }
    
    int forward(int v, int dst) const {
        assert(v >= 0 && v < (int) dep.size());
        assert(dst >= 0 && dst < (int) dep.size());
        assert(v != dst);
        int l = lca(v, dst);
        if (l == v) {
            return la(dst, dist(v, dst) - 1);
        } else {
            return par[v];
        }
    }

    int lca(int u, int v) const {
        assert(u >= 0 && u < (int) dep.size());
        assert(v >= 0 && v < (int) dep.size());
        while (u != v) {
            if (in[u] > in[v]) {
                std::swap(u, v);
            }
            if (hea[u] == hea[v]) {
                v = u;
            } else {
                v = par[hea[v]];
            }
        }
        return u;
    }

    int dist(int u, int v) const {
        assert(u >= 0 && u < (int) dep.size());
        assert(v >= 0 && v < (int) dep.size());
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }

    std::vector<std::pair<int, int>> path(int u, int v, bool edge) const {
        assert(u >= 0 && u < (int) dep.size());
        assert(v >= 0 && v < (int) dep.size());
        std::vector<std::pair<int, int>> fromu, fromv;
        bool rev = false;
        while (true) {
            if (u == v && edge) {
                break;
            }
            if (in[u] > in[v]) {
                std::swap(u, v);
                std::swap(fromu, fromv);
                rev ^= true;
            }
            if (hea[u] == hea[v]) {
                fromv.emplace_back(in[v], in[u] + (int)edge);
                v = u;
                break;
            } else {
                fromv.emplace_back(in[v], in[hea[v]]);
                v = par[hea[v]];
            }
        }
        if (rev) {
            std::swap(fromu, fromv);
        }
        std::reverse(fromv.begin(), fromv.end());
        fromu.reserve(fromv.size());
        for (auto [x, y] : fromv) {
            fromu.emplace_back(y, x);
        }
        return fromu;
    }
    
    int jump(int u, int v, int k) const {
        assert(u >= 0 && u < (int) dep.size());
        assert(v >= 0 && v < (int) dep.size());
        assert(k >= 0);
        int l = lca(u, v);
        int dis = dep[u] + dep[v] - 2 * dep[l];
        if (k > dis) {
            return -1;
        }
        if (k <= dep[u] - dep[l]) {
            return la(u, k);
        } else {
            return la(v, dis - k);
        }
    }
    
    int meet(int u, int v, int w) const {
        return lca(u, v) ^ lca(v, w) ^ lca(w, u);
    }
};

// ============

struct Converted {
    i32 n;
    Vec<Vec<i32>> tree;
    i32 rt;
    Vec<i32> a;
    i32 q;
    Vec<tuple<i32, i32, i32>> queries;  // (0, v, x) or (1, v, -1) or (1, n, -1)
};

Converted convert(i32 r, i32 c, i32 q, const Vec<Vec<i32>> &l,
                  const Vec<Vec<i32>> &p,
                  const Vec<tuple<i32, i32, i32, i32>> &queries) {
    Vec<i32> par(r * c, -1);
    auto find_root = [&](const auto &find_root, i32 v) -> i32 {
        if (par[v] == -1) {
            return v;
        } else {
            return par[v] = find_root(find_root, par[v]);
        }
    };
    Vec<pair<i32, i32>> events;
    REP(i, q) {
        auto [ty, x, y, val] = queries[i];
        if (ty == 1) {
            events.emplace_back(val, r * c + i);
        }
    }
    REP(i, r) REP(j, c) { events.emplace_back(l[i][j], i * c + j); }
    sort(ALL(events));
    const i32 dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
    Vec<Vec<i32>> tree(r * c);
    Vec<tuple<i32, i32, i32>> qs(q, make_tuple(0, 0, 0));
    for (auto [_, i] : events) {
        if (i < r * c) {
            i32 x = i / c;
            i32 y = i - x * c;
            REP(dir, 4) {
                i32 tx = x + dx[dir], ty = y + dy[dir];
                if (tx >= 0 && tx < r && ty >= 0 && ty < c &&
                    l[x][y] > l[tx][ty]) {
                    i32 tr = find_root(find_root, tx * c + ty);
                    if (tr != x * c + y) {
                        par[tr] = x * c + y;
                        tree[x * c + y].emplace_back(tr);
                        tree[tr].emplace_back(x * c + y);
                    }
                }
            }
        } else {
            i -= r * c;
            auto [_ty, x, y, val] = queries[i];
            if (val < l[x][y]) {
                qs[i] = make_tuple(1, r * c, -1);
            } else {
                i32 rt = find_root(find_root, x * c + y);
                qs[i] = make_tuple(1, rt, -1);
            }
        }
    }
    REP(i, q) {
        auto [ty, x, y, val] = queries[i];
        if (ty == 0) {
            qs[i] = make_tuple(0, x * c + y, val);
        }
    }
    i32 mx_x = -1, mx_y = -1, mx = -1;
    REP(i, r) REP(j, c) {
        if (chmax(mx, l[i][j])) {
            mx_x = i;
            mx_y = j;
        }
    }
    Vec<i32> a;
    a.reserve(r * c);
    REP(i, r) REP(j, c) { a.push_back(p[i][j]); }
    return Converted{r * c, tree, mx_x * c + mx_y, a, q, qs};
}

Vec<i32> solve(Converted prob) {
    HeavyLightDecomposition hld(prob.tree, prob.rt);
    i32 k = 0;
    REP(i, prob.n) { chmax(k, prob.a[i]); }
    for (auto [ty, x, y] : prob.queries) {
        if (ty == 0) {
            chmax(k, y);
        }
    }
    ++k;
    Vec<SparseSegmentTree<Add<i32>>> segs;
    segs.reserve(k);
    REP(i, k) { segs.emplace_back(SparseSegmentTree<Add<i32>>(prob.n + 1)); }
    SparseSegmentTree<Add<i32>> siz(prob.n);
    auto add = [&](i32 v, i32 x) -> void {
        for (auto [l, r] : hld.path(prob.rt, v, false)) {
            ++r;
            segs[x].update(l, segs[x].prod(l, l + 1) + 1);
            segs[x].update(r, segs[x].prod(r, r + 1) - 1);
        }
        i32 dep = hld.depth(v);
        i32 ok = -1, ng = dep + 1;
        while (ng - ok > 1) {
            i32 mid = (ok + ng) / 2;
            i32 u = hld.la(v, mid);
            if (segs[x].prod(0, hld.in_time(u) + 1) == 1) {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        if (ok != -1) {
            i32 u = hld.la(v, ok);
            for (auto [l, r] : hld.path(u, v, false)) {
                ++r;
                siz.update(l, siz.prod(l, l + 1) + 1);
                siz.update(r, siz.prod(r, r + 1) - 1);
            }
        }
    };
    auto sub = [&](i32 v, i32 x) -> void {
        for (auto [l, r] : hld.path(prob.rt, v, false)) {
            ++r;
            segs[x].update(l, segs[x].prod(l, l + 1) - 1);
            segs[x].update(r, segs[x].prod(r, r + 1) + 1);
        }
        i32 dep = hld.depth(v);
        i32 ok = -1, ng = dep + 1;
        while (ng - ok > 1) {
            i32 mid = (ok + ng) / 2;
            i32 u = hld.la(v, mid);
            if (segs[x].prod(0, hld.in_time(u) + 1) == 0) {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        if (ok != -1) {
            i32 u = hld.la(v, ok);
            for (auto [l, r] : hld.path(u, v, false)) {
                ++r;
                siz.update(l, siz.prod(l, l + 1) - 1);
                siz.update(r, siz.prod(r, r + 1) + 1);
            }
        }
    };
    REP(v, prob.n) { add(v, prob.a[v]); }
    Vec<i32> ans;
    for (auto [ty, x, y] : prob.queries) {
        if (ty == 0) {
            sub(x, prob.a[x]);
            prob.a[x] = y;
            add(x, prob.a[x]);
        } else {
            if (x == prob.n) {
                ans.push_back(0);
            } else {
                x = hld.in_time(x);
                ans.push_back(siz.prod(0, x + 1));
            }
        }
    }
    return ans;
}

int main() {
    i32 r, c, q;
    cin >> r >> c >> q;
    Vec<Vec<i32>> l(r, Vec<i32>(c));
    REP(i, r) REP(j, c) { cin >> l[i][j]; }
    Vec<Vec<i32>> p(r, Vec<i32>(c));
    REP(i, r) REP(j, c) { cin >> p[i][j]; }
    Vec<i32> dis;
    dis.reserve(r * c);
    REP(i, r) REP(j, c) { dis.push_back(l[i][j]); }
    sort(ALL(l));
    //REP(i, dis.size() - 1) { assert(dis[i] != dis[i + 1]); }
    Vec<tuple<i32, i32, i32, i32>> queries(q);
    for (auto &[ty, x, y, val] : queries) {
        cin >> ty >> y >> x >> val;
        --ty;
        --y;
        --x;
    }
    Converted prob = convert(r, c, q, l, p, queries);
    Vec<i32> ans = solve(prob);
    for (i32 ele : ans) {
        cout << ele << '\n';
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...