Submission #1265645

#TimeUsernameProblemLanguageResultExecution timeMemory
1265645witek_cppDungeon 3 (JOI21_ho_t5)C++20
0 / 100
405 ms132824 KiB
#include <iostream> #include <vector> #include <algorithm> #include <stack> #include <climits> using namespace std; typedef long long ll; #define st first #define nd second #define f(a, c, b) for (int a = c; b > a; a++) #define pb push_back #define all(a) a.begin(), a.end() #define wczytaj(a, c, n) a.resize(n); f(i, c, n) cin >> a[i]; #define sz(a) int(a.size()) #define wypisz(a, c) f(i, c, sz(a)) cout << a[i] << " "; cout << "\n"; const int MAXLOG = 18; const ll INF = 1'000'000'000'000'000LL; vector<ll> a; //jaka odleglosc vector<ll> b; //jaki koszt zakupu paliwa vector<pair<ll, ll>> f_drzewo; //drzewo funkcji liniowych (slope, intercept) vector<ll> odl_drzewo; //maksymalne drzewo po odl vector<pair<ll, int>> b_drzewo; //minimalne po koszcie paliwala (cost, idx) vector<ll> pref; //sumy prefiksowe do obliczania odleglosci vector<ll> dpl; //odleglosc do najbliższego tanszego na lewo (albo INF) vector<pair<ll, int>> dpr; //odleglosc do najbliższego tanszego na prawo i jego indeks vector<vector<pair<ll, int>>> jp; //jump pointers: (cost_sum, next_index) ll maks(int l, int r) { ll wnk = max(odl_drzewo[l], odl_drzewo[r]); while (r > (l + 1)) { if (l % 2 == 0) { wnk = max(wnk, odl_drzewo[l + 1]); } if (r % 2 == 1) { wnk = max(wnk, odl_drzewo[r - 1]); } l /= 2; r /= 2; } return wnk; } void zmien(int ind, pair<ll, ll> zmiana) { f_drzewo[ind] = zmiana; ind /= 2; while (ind) { f_drzewo[ind] = { f_drzewo[ind * 2].st + f_drzewo[(ind * 2) + 1].st, f_drzewo[ind * 2].nd + f_drzewo[(ind * 2) + 1].nd }; ind /= 2; } } int minn(int l, int r) { pair<ll, int> wnk = min(b_drzewo[l], b_drzewo[r]); while (r > (l + 1)) { if (l % 2 == 0) { wnk = min(wnk, b_drzewo[l + 1]); } if (r % 2 == 1) { wnk = min(wnk, b_drzewo[r - 1]); } l /= 2; r /= 2; } return wnk.nd; } pair<ll, ll> zlozenie(int l, int r) { pair<ll, ll> wnk = {0, 0}; if (r < l) return wnk; if (r == l) return f_drzewo[r]; wnk = {f_drzewo[r].st + f_drzewo[l].st, f_drzewo[r].nd + f_drzewo[l].nd}; while (r > (l + 1)) { if (l % 2 == 0) { wnk.st += f_drzewo[l + 1].st; wnk.nd += f_drzewo[l + 1].nd; } if (r % 2 == 1) { wnk.st += f_drzewo[r - 1].st; wnk.nd += f_drzewo[r - 1].nd; } r /= 2; l /= 2; } return wnk; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n, q; if (!(cin >> n >> q)) return 0; a.resize(n); b.resize(n); f(i, 0, n) cin >> a[i]; f(i, 0, n) cin >> b[i]; pref.resize(n + 1); pref[0] = 0; f(i, 1, n + 1) pref[i] = pref[i - 1] + a[i - 1]; dpl.resize(n); { stack<int> stos; f(i, 0, n) { while (sz(stos) && b[stos.top()] > b[i]) stos.pop(); if (sz(stos)) { dpl[i] = pref[i] - pref[stos.top()]; } else { dpl[i] = INF; } stos.push(i); } } dpr.resize(n); { stack<int> stos; for (int i = n - 1; i >= 0; i--) { while (sz(stos) && b[stos.top()] >= b[i]) stos.pop(); if (sz(stos)) { dpr[i] = {pref[stos.top()] - pref[i], stos.top()}; } else { dpr[i] = {INF, -1}; } stos.push(i); } } int stala = 1; while (stala < n) stala *= 2; odl_drzewo.assign(2 * stala, -INF); f(i, 0, n) odl_drzewo[i + stala] = a[i]; for (int j = stala - 1; j > 0; j--) { odl_drzewo[j] = max(odl_drzewo[j * 2], odl_drzewo[(2 * j) + 1]); } b_drzewo.assign(2 * stala, {INF, INT_MAX}); f(i, 0, n) b_drzewo[i + stala] = {b[i], i}; for (int j = stala - 1; j > 0; j--) { b_drzewo[j] = min(b_drzewo[j * 2], b_drzewo[(j * 2) + 1]); } jp.assign(MAXLOG, vector<pair<ll, int>>(n)); f(i, 0, n) { if (dpr[i].st == INF) { jp[0][i] = {0, i}; } else { jp[0][i] = {b[i] * dpr[i].st, dpr[i].nd}; } } f(j, 1, MAXLOG) { f(i, 0, n) { jp[j][i] = { jp[j - 1][i].st + jp[j - 1][jp[j - 1][i].nd].st, jp[j - 1][jp[j - 1][i].nd].nd }; } } // inicjalizacja f_drzewo (liście) f_drzewo.assign(2 * stala, {0, 0}); f(i, 0, n) { f_drzewo[i + stala] = {b[i], 0}; // zostawiam twoją pierwotną inicjalizację liści } for (int j = stala - 1; j > 0; j--) { // POPRAWKA: sumujemy też .nd (wcześniej było 0) f_drzewo[j] = { f_drzewo[j * 2].st + f_drzewo[(j * 2) + 1].st, f_drzewo[j * 2].nd + f_drzewo[(j * 2) + 1].nd }; } vector<pair<ll, pair<int, pair<int, pair<ll, ll>>>>> zamiatanie; //{u, {rodzaj, {ind, {slope, intercept}}}} f(i, 0, n) { // eventy (tak jak w Twoim kodzie) ll mn = min(dpl[i], dpr[i].st); ll mx = max(dpl[i], dpr[i].st); zamiatanie.pb({mn, {0, {i, {0, mn * b[i]}}}}); zamiatanie.pb({mx, {0, {i, {-b[i], (dpl[i] + dpr[i].st) * b[i]}}}}); zamiatanie.pb({dpl[i] + dpr[i].st, {0, {i, {0, 0}}}}); } vector<pair<pair<int, int>, ll>> pytania(q); vector<ll> odp(q); int ile_zrobione = 0; f(i, 0, q) { int l, r; ll u; cin >> l >> r >> u; l--; r--; pytania[i] = {{l, r}, u}; if (maks(l + stala, r + stala - 1) > u) { ile_zrobione++; odp[i] = -1; } else { zamiatanie.pb({u, {1, {i, {-1, -1}}}}); } } sort(all(zamiatanie)); reverse(all(zamiatanie)); while (ile_zrobione < q) { if (zamiatanie.empty()) { cout << "blad\n"; return 0; } auto ev = zamiatanie.back(); zamiatanie.pop_back(); int rodzaj = ev.nd.st; int ind = ev.nd.nd.st; if (rodzaj == 0) { zmien(ind + stala, ev.nd.nd.nd); continue; } ll aktl_u = pytania[ind].nd; int l, r, mid; int koniec = pytania[ind].st.nd; r = pytania[ind].st.nd - 1; l = pytania[ind].st.st; while (r > l) { mid = (l + r) / 2; if ((pref[koniec] - pref[mid]) <= aktl_u) { r = mid; } else { l = mid + 1; } } int suf_min = minn(r + stala, koniec - 1 + stala); int poc = pytania[ind].st.st; int skacze = poc; ll ile_doda_skaczac = 0; for (int j = MAXLOG - 1; j >= 0; j--) { int to = jp[j][skacze].nd; if ((pref[to] - pref[poc]) <= aktl_u && to < koniec) { ile_doda_skaczac += jp[j][skacze].st; skacze = to; } } pair<ll, ll> nowa_funkcja = zlozenie(skacze + stala + 1, suf_min - 1 + stala); ll ile_doda_punkt = 0; if (skacze < suf_min) { // POPRAWKA: ograniczamy do środka (suf_min), a nie do 'koniec' ll limit = pref[suf_min] - pref[skacze]; ile_doda_punkt = min(limit, min(aktl_u, dpr[skacze].st)) * b[skacze]; } ll ile_doda_srodek = aktl_u * nowa_funkcja.st + nowa_funkcja.nd; ll ile_doda_kon = ((pref[koniec] - pref[suf_min]) * b[suf_min]); if (dpl[suf_min] <= (pref[suf_min] - pref[poc])) { ile_doda_kon -= (b[suf_min] * max((ll)0, (aktl_u - dpl[suf_min]))); } odp[ind] = ile_doda_skaczac + ile_doda_srodek + ile_doda_kon + ile_doda_punkt; ile_zrobione++; } for (ll ele : odp) { cout << ele << "\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...