Submission #1154410

#TimeUsernameProblemLanguageResultExecution timeMemory
1154410Pichon5Meteors (POI11_met)C++20
100 / 100
676 ms38680 KiB
#include <bits/stdc++.h> using namespace std; #define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define ll long long #define vll vector<ll> #define pb push_back #define F first #define S second const int tam = 300030; const ll INF = 1e16; // BIT (Fenwick Tree) unsigned long long T[2 * tam]; ll n, m, k; vector<vll> G; // Para cada nodo (1-indexado) se guardan posiciones (en [1, m]) ll E[tam]; // Para cada nodo se tiene un umbral ll res[tam]; // Respuesta para cada nodo (mínimo update en el que se cumple la condición) // Las queries (updates) se almacenan en Q: // Q[i] = { {l, r}, val } indica que se debe aplicar: // update(l, val); update(r+1, -val); // (además, si r < l se “envuelve” el intervalo) vector<pair<pair<ll,ll>, ll>> Q; void update(int pos, int val) { while (pos <= m) { T[pos] += val; pos += (pos & -pos); } } ll query(ll pos) { unsigned long long ans = 0; while (pos > 0) { ans += T[pos]; pos -= (pos & -pos); } return ans; } // Definimos dos tipos de acción para simular la recursión enum ActionType { PROCESS, ROLLBACK }; // Una acción de la pila contendrá: // - Para PROCESS: el intervalo de updates [b, e] y la lista de nodos a evaluar. // - Para ROLLBACK: el intervalo [b, mid] que se usó en un PROCESS para luego deshacer los BIT updates. struct Action { ActionType type; ll b, e, mid; // Para PROCESS: se usan b y e; para ROLLBACK: se usan b y mid (e no importa) vll nodes; // Solo para PROCESS. }; // Función iterativa de parallel binary search usando una pila (stack) void parallel_stack() { stack<Action> st; // Estado inicial: buscamos en el rango de updates [0, k-1] para todos los nodos (1..n) vll allNodes; for (int i = 1; i <= n; i++) { allNodes.pb(i); } st.push({PROCESS, 0, k - 1, -1, allNodes}); while (!st.empty()) { Action cur = st.top(); st.pop(); if (cur.type == PROCESS) { // Si no hay nodos o el intervalo de updates es inválido, saltamos if (cur.nodes.empty() || cur.b > cur.e) continue; ll mid = (cur.b + cur.e) / 2; // Aplicamos los BIT updates para los updates en el intervalo [cur.b, mid] for (ll i = cur.b; i <= mid; i++) { ll l = Q[i].F.F, r = Q[i].F.S, val = Q[i].S; update(l, val); if (r < l) { update(1, val); update(m + 1, -val); } update(r + 1, -val); } // Separamos los nodos en dos grupos: // A: aquellos que cumplen la condición (suma >= E[node]) // B: los que no cumplen. vll A, B; for (ll node : cur.nodes) { ll sum = 0; for (auto pos : G[node]) { sum += query(pos); if (sum >= 1e10) break; // corte temprano } if (sum >= E[node]) { A.pb(node); res[node] = min(res[node], mid + 1); // mid es 0-indexado, guardamos mid+1 } else { B.pb(node); } } // Para simular la recursión: // Se debe procesar primero el branch derecho (con BIT aún aplicado), // luego hacer rollback de los updates, y finalmente procesar el branch izquierdo. // Debido a LIFO, empujamos en el orden inverso: // 1. Push PROCESS para el branch izquierdo ([cur.b, mid-1], nodos A) si no está vacío. // 2. Push ROLLBACK (para deshacer updates en [cur.b, mid]). // 3. Push PROCESS para el branch derecho ([mid+1, cur.e], nodos B) si no está vacío. if (!A.empty() && cur.b <= mid - 1) { st.push({PROCESS, cur.b, mid - 1, -1, A}); } st.push({ROLLBACK, cur.b, 0, mid, {}}); // ROLLBACK: guardamos b y mid. if (!B.empty() && mid + 1 <= cur.e) { st.push({PROCESS, mid + 1, cur.e, -1, B}); } } else { // Acción ROLLBACK: deshacemos los BIT updates aplicados en [cur.b, cur.mid] for (ll i = cur.b; i <= cur.mid; i++) { ll l = Q[i].F.F, r = Q[i].F.S; ll val = -Q[i].S; // Inverso del valor aplicado anteriormente update(l, val); if (r < l) { update(1, val); update(m + 1, -val); } update(r + 1, -val); } } } } int main(){ fast; ll x; cin >> n >> m; // Para cada nodo (1 a n) se guarda una lista de posiciones (índices de update) que le afectan. G.assign(n + 1, vll()); for (int i = 1; i <= m; i++){ cin >> x; G[x].pb(i); } for (int i = 1; i <= n; i++){ cin >> E[i]; } cin >> k; for (int i = 0; i < k; i++){ ll l, r, val; cin >> l >> r >> val; Q.pb({{l, r}, val}); } // Inicializamos res para cada nodo; si no se alcanza, se mantiene k+1 for (int i = 0; i <= n; i++) { res[i] = k + 1; } // Aseguramos que el BIT esté en cero memset(T, 0, sizeof(T)); parallel_stack(); for (int i = 1; i <= n; i++){ if (res[i] == k + 1) cout << "NIE" << "\n"; else cout << res[i] << "\n"; } return 0; }
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...