Submission #216901

#TimeUsernameProblemLanguageResultExecution timeMemory
216901rama_pangHarvest (JOI20_harvest)C++14
100 / 100
766 ms95780 KiB
#include <bits/stdc++.h> using namespace std; mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()); long long floor_div(long long a, long long b) { // integer floor division return (a / b) - ((a ^ b) < 0 && a % b); } namespace Treap { struct TreapNode { int prior, sz; long long value, lazy = 0; TreapNode *l, *r; TreapNode(long long v = 0) : prior(rnd()), sz(1), value(v), l(NULL), r(NULL) {} }; using pt = TreapNode*; int sz(pt t) { return t ? t->sz : 0; } void upd(pt t) { if (t) t->sz = sz(t->l) + sz(t->r) + 1; } void apply(pt t, long long x) { if (t) t->value += x, t->lazy += x; } void push(pt t) { if (!t) return; apply(t->l, t->lazy); apply(t->r, t->lazy); t->lazy = 0; } void split(pt t, pt &l, pt &r, long long key) { // l will have all values <= key push(t); if (!t) { l = r = NULL; } else if (t->value > key) { split(t->l, l, t->l, key), r = t; } else { split(t->r, t->r, r, key), l = t; } upd(t); } void merge(pt &t, pt l, pt r) { push(l), push(r); if (!l || !r) { t = l ? l : r; } else if (l->prior > r->prior) { merge(l->r, l->r, r), t = l; } else { merge(r->l, l, r->l), t = r; } upd(t); } void erase(pt t, long long x) { push(t); if (!t) return; if (t->value > x) { erase(t->l, x); } else if (t->value < x) { erase(t->r, x); } else if (t->value == x) { pt to_be_del = t; merge(t, t->l, t->r); delete to_be_del; } upd(t); } void clear(pt t) { if (!t) return; clear(t->l); clear(t->r); t = NULL; delete t; } void get(pt t, vector<long long> &res) { push(t); if (!t) return; get(t->l, res); res.emplace_back(t->value); get(t->r, res); } void update(pt &root, long long x) { // increase all elements in treap by x under modulo mod pt l, r; apply(root, x); } void insert(pt &root, long long x) { pt l, r; split(root, l, r, x); merge(l, l, new TreapNode(x)); merge(root, l, r); } vector<long long> get(pt root) { vector<long long> res; get(root, res); return res; } int order_of_key(pt &root, long long x) { // find number of values <= x pt l, r; int res; split(root, l, r, x); res = sz(l); merge(root, l, r); return res; } pt unite(pt l, pt r) { push(l), push(r); if (!l) return r; if (!r) return l; if (l->prior < r->prior) swap(l, r); pt lt, rt; split(r, lt, rt, l->value); l->l = unite(l->l, lt); l->r = unite(l->r, rt); upd(l); return l; } } int N, M, L, C; vector<int> A, B; vector<int> next_vertex; // next vertex A[] after a tree has just finished visited A[i] and gave it an apple vector<int> next_distance; // distance to next_vertex (time needed) vector<int> first_vertex; // first vertex that tree[] meets vector<int> first_distance; // the distance in time vector<bool> in_cycle; // whether a vertex v is part of a cycle or not vector<long long> cycle_length; // the length of a cycle vertex v is part of vector<int> cycle_start; // the start of the cycle, where pos[start] = 0 vector<long long> pos_in_cycle; // the positions / distance namespace Naive { // O(N^2 log N) solution, unoptimized version of the main ideas for full solution vector<multiset<long long>> meeting_time; // first time a vertex meets certain trees under modulo len vector<long long> initial_overflow; // sum of all floor(i / len) for meeting_time (the original value) void NaiveGetMeetingTime() { // Naive O(N^2 log N) meeting_time.resize(N); for (int ci = 0; ci < M; ci++) { int v = first_vertex[ci]; long long len = first_distance[ci]; vector<bool> vis(N, false); do { vis[v] = true; meeting_time[v].emplace(len); len += next_distance[v]; v = next_vertex[v]; } while (!vis[v]); } } long long NaiveQuery(int V, long long T) { if (!in_cycle[V]) { int lb = 0; // lower bound, will be implemented later for (auto &i : meeting_time[V]) { if (i <= T) lb++; } return lb; } // V is in a cycle long long len = cycle_length[V]; long long res = 0; for (auto &i : meeting_time[V]) { long long cur = floor_div(T, len) - floor_div(i, len) + ((i % len) <= (T % len)); // equivalent to div(T - i, len) + 1 res += max(cur, 0ll); } return res; } } void BuildGraph() { { // build initial graph next_vertex.resize(N); next_distance.resize(N); for (int i = 0; i < N; i++) { int next_loc = (A[i] - C) % L; // go counter clockwise if (next_loc < 0) next_loc += L; if (next_loc < A[0]) next_loc += L; next_vertex[i] = upper_bound(begin(A), end(A), next_loc) - begin(A) - 1; next_distance[i] = C + (next_loc - A[next_vertex[i]]); } first_vertex.resize(M); first_distance.resize(M); for (int i = 0; i < M; i++) { int next_loc = B[i]; // go counter clockwise if (next_loc < A[0]) next_loc += L; first_vertex[i] = upper_bound(begin(A), end(A), next_loc) - begin(A) - 1; first_distance[i] = (next_loc - A[first_vertex[i]]); } } { // find information about the cycles int mark = 0; vector<int> vis(N, 0); in_cycle.resize(N, false); cycle_length.resize(N, -1); cycle_start.resize(N, -1); pos_in_cycle.resize(N, -1); auto Calc = [&](int i) { mark++; int cur = i; do { vis[cur] = mark; cur = next_vertex[cur]; } while (!vis[cur]); if (vis[cur] != mark) { // this cycle is already processed before return; } int st = cur; long long len = 0; do { cycle_start[cur] = st; pos_in_cycle[cur] = len; in_cycle[cur] = true; len += next_distance[cur]; cur = next_vertex[cur]; } while (cur != st); cycle_length[cur] = len; }; // process cycles for (int i = 0; i < N; i++) { if (vis[i]) continue; Calc(i); } } } vector<long long> answer; vector<vector<pair<long long, int>>> query; // query[V] = (T, query_index) vector<vector<long long>> first_meeting_cycle; // first time trees meet a cycle (time) vector<vector<long long>> first_meeting_tree; // first time trees meet a non-cucle (which musy be a tree) (time) void SolveTree() { // also solves the case for broken cycle vector<vector<int>> adj(N); for (int i = 0; i < N; i++) { if (in_cycle[i] && cycle_start[i] == next_vertex[i]) continue; // the edge to be cut in a broken cycle if (!in_cycle[i] && in_cycle[next_vertex[i]]) continue; adj[next_vertex[i]].emplace_back(i); } vector<Treap::pt> treap(N, NULL); function<void(int)> dfs = [&](int cur) { for (auto &nxt : adj[cur]) { dfs(nxt); treap[cur] = unite(treap[cur], treap[nxt]); } for (auto &nw : first_meeting_tree[cur]) { Treap::insert(treap[cur], nw); } for (auto &q : query[cur]) { answer[q.second] = Treap::order_of_key(treap[cur], q.first); } Treap::update(treap[cur], next_distance[cur]); }; // calculate answer for tree part for (int i = 0; i < N; i++) { if (!in_cycle[i] && in_cycle[next_vertex[i]]) { dfs(i); // next_vertex is now part of a cycle vector<long long> elements = Treap::get(treap[i]); Treap::clear(treap[i]); for (auto &e : elements) { first_meeting_cycle[next_vertex[i]].emplace_back(e); first_meeting_tree[next_vertex[i]].emplace_back(e); } } } // calculate contribution of broken cycle for (int i = 0; i < N; i++) { if (in_cycle[i] && cycle_start[i] == next_vertex[i]) { dfs(i); Treap::clear(treap[i]); } } } void SolveCycle(int r) { // solves the case for cycles, excluding the broken cycle case long long initial_overflow = 0; long long len = cycle_length[r]; int cur = r; Treap::pt treap = NULL; vector<long long> all_meeting_time; vector<pair<long long, int>> all_queries; // pair of (T - pos[orginal_position], query_id) do { for (auto &nw : first_meeting_cycle[cur]) { long long distance = nw + (len - pos_in_cycle[cur]); all_meeting_time.emplace_back(distance); } for (auto &q : query[cur]) { all_queries.emplace_back(q.first - pos_in_cycle[cur], q.second); } cur = next_vertex[cur]; } while (cur != r); sort(begin(all_meeting_time), end(all_meeting_time), greater<long long>()); sort(begin(all_queries), end(all_queries)); for (auto &q : all_queries) { while (!all_meeting_time.empty() && all_meeting_time.back() <= q.first) { Treap::insert(treap, all_meeting_time.back() % len); initial_overflow += floor_div(all_meeting_time.back(), len); all_meeting_time.pop_back(); } answer[q.second] += 1ll * floor_div(q.first, len) * Treap::sz(treap) - initial_overflow + Treap::order_of_key(treap, q.first % len); } Treap::clear(treap); } void SolveCycle() { for (int i = 0; i < N; i++) { if (in_cycle[i] && cycle_start[i] == i) { SolveCycle(i); } } } void SolveQuery() { first_meeting_cycle.resize(N); first_meeting_tree.resize(N); for (int i = 0; i < M; i++) { int v = first_vertex[i]; if (in_cycle[v]) { first_meeting_cycle[v].emplace_back(first_distance[i]); first_meeting_tree[v].emplace_back(first_distance[i]); } else { first_meeting_tree[v].emplace_back(first_distance[i]); } } SolveTree(); SolveCycle(); } void Solve() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); cin >> N >> M >> L >> C; A.resize(N), B.resize(M); for (auto &i : A) cin >> i; for (auto &i : B) cin >> i; int Q; cin >> Q; answer.resize(Q, -1); query.resize(N); for (int i = 0; i < Q; i++) { int V; long long T; cin >> V >> T; query[--V].emplace_back(T, i); } BuildGraph(); SolveQuery(); for (int i = 0; i < Q; i++) { cout << answer[i] << "\n"; } } int main() { Solve(); return 0; }

Compilation message (stderr)

harvest.cpp: In function 'void Treap::update(Treap::TreapNode*&, long long int)':
harvest.cpp:88:8: warning: unused variable 'l' [-Wunused-variable]
     pt l, r;
        ^
harvest.cpp:88:11: warning: unused variable 'r' [-Wunused-variable]
     pt l, r;
           ^
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...