제출 #1323313

#제출 시각아이디문제언어결과실행 시간메모리
1323313buzdi게임 (IOI13_game)C++20
80 / 100
3675 ms146792 KiB
#include "game.h"
#include <vector>
#include <numeric>
#include <algorithm>

using namespace std;

// Standard GCD function
long long gcd2(long long X, long long Y) {
    long long tmp;
    while (X != 0 && Y != 0) {
        if (X > Y) X %= Y;
        else Y %= X;
    }
    return X + Y;
}

// Inner Segment Tree Node (Y-dimension)
struct NodeY {
    int left = 0;
    int right = 0;
    long long val = 0;
};

// Outer Segment Tree Node (X-dimension)
struct NodeX {
    int left = 0;
    int right = 0;
    int rootY = 0; // Root of the inner tree for this X-range
};

// Memory pools
// We reserve enough space. N * log(R) * log(C) roughly.
// Max nodes estimate: 22000 ops * 30 * 30 ~ 20M nodes.
const int MAX_NODES = 25000000; 

// We use global vectors to act as our "heap"
// Index 0 is reserved as "null"
vector<NodeY> treeY;
vector<NodeX> treeX;

int rootX = 0;
int ROWS, COLS;

// --- Inner Tree (Y-axis) Operations ---

// Update the inner tree at position 'pos' with 'val'
// node_idx: current node in Y-tree
// l, r: current range coverage of this node
void updateY(int &node_idx, int l, int r, int pos, long long val) {
    if (!node_idx) {
        node_idx = treeY.size();
        treeY.push_back({0, 0, 0});
    }
    
    if (l == r) {
        treeY[node_idx].val = val;
        return;
    }
    
    int mid = l + (r - l) / 2;
    if (pos <= mid) {
        updateY(treeY[node_idx].left, l, mid, pos, val);
    } else {
        updateY(treeY[node_idx].right, mid + 1, r, pos, val);
    }
    
    long long valL = treeY[node_idx].left ? treeY[treeY[node_idx].left].val : 0;
    long long valR = treeY[node_idx].right ? treeY[treeY[node_idx].right].val : 0;
    treeY[node_idx].val = gcd2(valL, valR);
}

// Query the inner tree
long long queryY(int node_idx, int l, int r, int ql, int qr) {
    if (!node_idx || l > qr || r < ql) return 0;
    if (l >= ql && r <= qr) return treeY[node_idx].val;
    
    int mid = l + (r - l) / 2;
    return gcd2(queryY(treeY[node_idx].left, l, mid, ql, qr),
                queryY(treeY[node_idx].right, mid + 1, r, ql, qr));
}

// --- Outer Tree (X-axis) Operations ---

// Helper to get value at a specific column 'posK' from an existing Y-tree
long long get_val_from_Y(int nodeX_idx, int posK) {
    if (!nodeX_idx) return 0;
    // We strictly query a single point (posK, posK) in the Y-tree
    return queryY(treeX[nodeX_idx].rootY, 0, COLS - 1, posK, posK);
}

// Update the outer tree
// r, c: target coordinates
// val: new value
void updateX(int &node_idx, int l, int r, int target_r, int target_c, long long val) {
    if (!node_idx) {
        node_idx = treeX.size();
        treeX.push_back({0, 0, 0});
    }

    // Whether leaf or internal, we must update the Y-tree associated with this X-node.
    
    if (l == r) {
        // Leaf in X-tree: represents exactly one row.
        // Just update the Y-tree normally.
        updateY(treeX[node_idx].rootY, 0, COLS - 1, target_c, val);
    } else {
        int mid = l + (r - l) / 2;
        if (target_r <= mid) {
            updateX(treeX[node_idx].left, l, mid, target_r, target_c, val);
        } else {
            updateX(treeX[node_idx].right, mid + 1, r, target_r, target_c, val);
        }
        
        // Internal node logic:
        // The value at (target_r, target_c) has changed.
        // This X-node represents a range of rows. The Y-tree at this node 
        // must store gcd( lower_half_row_val, upper_half_row_val ) at column target_c.
        
        long long v1 = get_val_from_Y(treeX[node_idx].left, target_c);
        long long v2 = get_val_from_Y(treeX[node_idx].right, target_c);
        long long new_gcd = gcd2(v1, v2);
        
        updateY(treeX[node_idx].rootY, 0, COLS - 1, target_c, new_gcd);
    }
}

long long queryX(int node_idx, int l, int r, int r1, int r2, int c1, int c2) {
    if (!node_idx || l > r2 || r < r1) return 0;
    
    if (l >= r1 && r <= r2) {
        // Entire X-range is within query.
        // Query the Y-tree for the column range.
        return queryY(treeX[node_idx].rootY, 0, COLS - 1, c1, c2);
    }
    
    int mid = l + (r - l) / 2;
    return gcd2(queryX(treeX[node_idx].left, l, mid, r1, r2, c1, c2),
                queryX(treeX[node_idx].right, mid + 1, r, r1, r2, c1, c2));
}

// --- Interface Functions ---

void init(int R, int C) {
    ROWS = R;
    COLS = C;
    
    // Reserve memory to prevent reallocations invalidating references 
    // (though indices are safe, resizing is slow)
    treeY.reserve(MAX_NODES);
    treeX.reserve(200000); // Outer tree has much fewer nodes
    
    // Push dummy 0-th node
    treeY.push_back({0, 0, 0});
    treeX.push_back({0, 0, 0});
}

void update(int P, int Q, long long K) {
    updateX(rootX, 0, ROWS - 1, P, Q, K);
}

long long calculate(int P, int Q, int U, int V) {
    return queryX(rootX, 0, ROWS - 1, P, U, Q, V);
}
#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...