#include "game.h"
#include <cassert>
#include <vector>
#include <map>
using namespace std;
long long gcd2(long long X, long long Y);
template<class Key, class T, class Compare, class Allocator>
T getOrDefault(const map<Key, T, Compare, Allocator> &m, const Key &k, const T &def) {
auto it = m.find(k);
return it == m.end() ? def : it->second;
}
// Intended for nonempty intervals.
struct Interval {
int L, U;
inline bool operator==(const Interval &other) const = default;
inline int length() const {return U-L;}
inline bool contains(const Interval &x) const { return L <= x.L && x.U <= U; }
inline bool contains(int x) const { return L <= x && x < U;}
inline bool nonempty() const { return length() > 0; }
inline int mid() const { return L + (U-L)/2;}
inline Interval leftHalf() const { return Interval {L, mid()};}
inline Interval rightHalf() const { return Interval {mid(), U};}
};
// Intended for intervals known to intersect.
inline Interval intersection(const Interval &x, const Interval &y) {
return {max(x.L, y.L), min(x.U, y.U)};
}
inline bool intersects(const Interval &x, const Interval &y) {
return intersection(x, y).nonempty();
}
class LazySegTreeIntervals {
private:
int nextId = 0;
struct Node {
int id;
Node *left, *right;
Node(int id_) : id(id_), left(nullptr), right(nullptr) {}
};
struct NodePtrIvl {
Node *node;
Interval ivl;
NodePtrIvl leftHalf() const { return {node->left, ivl.leftHalf()};}
NodePtrIvl rightHalf() const { return {node->right, ivl.rightHalf()};}
};
NodePtrIvl root;
inline Node *createNewNode() {
return new Node(nextId++);
}
void decompose(const NodePtrIvl &nodePtrIvl, const Interval &queryIvl, vector<int> &ids) const {
Node *node = nodePtrIvl.node;
Interval nodeIvl = nodePtrIvl.ivl;
assert(nodeIvl.contains(queryIvl));
if(nodeIvl == queryIvl) {
ids.push_back(node->id);
return;
}
auto leftIvl = nodeIvl.leftHalf();
auto rightIvl = nodeIvl.rightHalf();
if(node->left && intersects(leftIvl, queryIvl)) {
decompose(nodePtrIvl.leftHalf(), intersection(leftIvl, queryIvl), ids);
}
if(node->right && intersects(rightIvl, queryIvl)) {
decompose(nodePtrIvl.rightHalf(), intersection(rightIvl, queryIvl), ids);
}
}
public:
struct ParentChildIds {
int p, c1, c2;
};
private:
inline ParentChildIds getParentChildId(Node *node) {
return {node->id, node->left ? node->left->id : NO_ID, node->right? node->right->id : NO_ID};
}
public:
inline LazySegTreeIntervals(int N) : root(createNewNode(), {0,N}) {
assert(N >= 1);
}
constexpr static int NO_ID = -1;
// Ensure that all nodes on the path from the root [0,N) to the
// leaf [x, x+1) exist. For each such node, returns a tuple
// with the id of that node and both its children (or NO_ID if a child
// doesn't exist). These are retured in order from root to leaf.
vector<ParentChildIds> ensureNodesAndGetIds(int x) {
assert(root.ivl.contains(x));
vector<ParentChildIds> ids;
ids.reserve(32); // Upper bound for maximum height of the tree for the maximum N
NodePtrIvl cur = root;
while(true) {
assert(cur.node && cur.ivl.contains(x));
if(cur.ivl.length() == 1) {
ids.push_back(getParentChildId(cur.node));
break;
}
int mid = cur.ivl.mid();
if(x < mid) {
if (!cur.node->left) cur.node->left = createNewNode();
ids.push_back(getParentChildId(cur.node));
cur = cur.leftHalf();
} else {
if (!cur.node->right) cur.node->right = createNewNode();
ids.push_back(getParentChildId(cur.node));
cur = cur.rightHalf();
}
}
return ids;
}
// Try to decompose [a,b) into constituent intervals as
// if this was a full segtree. Let X be the set of values for
// which createIntervalsAndGetIds has been called.
// Consider the ids returned by this method, and
// let Y be the union of their corresponding intervals.
// Then we have Y intersection X = [a,b) intersection X.
// If this was a full segtree, we would have Y = [a,b).
// Of course, we also have that the size of the returned vector
// is at most logarithmic in N.
vector<int> decomposeIntervalAndGetIds(const Interval &ivl) const {
vector<int> ids;
decompose(root, ivl, ids);
return ids;
}
};
LazySegTreeIntervals Rtree(1), Ctree(1);
// A key (x,y) corresponds to node with id x in Rtree and
// a node with id y in Ctree. Each of those nodes represent an
// interval of indices. Their product represents a subrectangle
// of cells. The value is the gcd of the values in those cells.
map<pair<int, int>, long long> gcds;
void init(int R, int C) {
Rtree = LazySegTreeIntervals(R);
Ctree = LazySegTreeIntervals(C);
}
void update(int P, int Q, long long K) {
// Each of these is ordered from root to leaf.
vector<LazySegTreeIntervals::ParentChildIds> rIds = Rtree.ensureNodesAndGetIds(P);
vector<LazySegTreeIntervals::ParentChildIds> cIds = Ctree.ensureNodesAndGetIds(Q);
assert(!rIds.empty());
assert(!cIds.empty());
for (auto rit = rIds.rbegin(); rit != rIds.rend(); ++rit)
for (auto cit = cIds.rbegin(); cit != cIds.rend(); ++cit) {
if (rit == rIds.rbegin() && cit == cIds.rbegin()) { // base case
gcds[{rIds.rbegin()->p, cIds.rbegin()->p}] = K;
continue;
}
// We have a rectangle which can be split in half in two ways
// We can choose either arbitrarily, except for a 1xN or Nx1
// rectangle, in which case there is only one choice.
if (rit == rIds.rbegin()) {
// cit->c1 or cit->c2 can be NO_ID if that child doesn't exist (hasn't been populated)
// in the tree. This is not a problem, since in that case that key doesn't exist
// in the map, so 0 is returned, as desired.
gcds[{rit->p, cit->p}] =
gcd2(getOrDefault(gcds, {rit->p, cit->c1}, 0LL), getOrDefault(gcds, {rit->p, cit->c2}, 0LL));
} else {
gcds[{rit->p, cit->p}] =
gcd2(getOrDefault(gcds, {rit->c1, cit->p}, 0LL), getOrDefault(gcds, {rit->c2, cit->p}, 0LL));
}
}
}
long long calculate(int P, int Q, int U, int V) {
vector<int> rIds = Rtree.decomposeIntervalAndGetIds({P, U+1});
vector<int> cIds = Ctree.decomposeIntervalAndGetIds({Q, V+1});
long long ans = 0;
for(int rId : rIds)
for(int cId : cIds) {
ans = gcd2(ans, getOrDefault(gcds, {rId, cId}, 0LL));
if (ans==1) { return 1; }
}
return ans;
}
inline long long gcd2(long long X, long long Y) {
long long tmp;
while (X != Y && Y != 0) {
tmp = X;
X = Y;
Y = tmp % Y;
}
return X;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |