Submission #1156058

#TimeUsernameProblemLanguageResultExecution timeMemory
1156058tesseractGame (IOI13_game)C++20
63 / 100
7388 ms321536 KiB
#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; Interval ivl; Node *left, *right; Node(int id_, const Interval &ivl_) : id(id_), ivl(ivl_), left(nullptr), right(nullptr) {} inline int length() const { return ivl.length();} }; Node *root; int N; inline Node *createNewNode(const Interval &ivl) { return new Node(nextId++, ivl); } void decompose(const Node *node, const Interval &queryIvl, vector<int> &ids) const { assert(node->ivl.contains(queryIvl)); if(node->ivl == queryIvl) { ids.push_back(node->id); return; } if(node->left && intersects(node->left->ivl, queryIvl)) { decompose(node->left, intersection(node->left->ivl, queryIvl), ids); } if(node->right && intersects(node->right->ivl, queryIvl)) { decompose(node->right, intersection(node->right->ivl, 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_) : N(N_) { assert(N >= 1); root = createNewNode({0,N}); } 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(0 <= x && x < N); vector<ParentChildIds> ids; ids.reserve(32); // Upper bound for maximum height of the tree for the maximum N Node *cur = root; while(true) { assert(cur && cur->ivl.contains(x)); if(cur->ivl.length() == 1) { ids.push_back(getParentChildId(cur)); break; } int mid = cur->ivl.mid(); if(x < mid) { if (!cur->left) cur->left = createNewNode(cur->ivl.leftHalf()); ids.push_back(getParentChildId(cur)); cur = cur->left; } else { if (!cur->right) cur->right = createNewNode(cur->ivl.rightHalf()); ids.push_back(getParentChildId(cur)); cur = cur->right; } } 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 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...