제출 #1136861

#제출 시각아이디문제언어결과실행 시간메모리
1136861panDungeon 3 (JOI21_ho_t5)C++20
100 / 100
345 ms45952 KiB
#include <bits/stdc++.h> //#include "includeall.h" //#include <ext/pb_ds/assoc_container.hpp> //#include <ext/pb_ds/tree_policy.hpp> #define endl '\n' #define f first #define s second #define pb push_back #define mp make_pair #define lb lower_bound #define ub upper_bound #define all(x) x.begin(), x.end() #define discretize(x) sort(x.begin(), x.end()); x.erase(unique(x.begin(), x.end()), x.end()); #define show(x) cerr << #x << " is " << x << endl; #define show2(x,y) cerr << #x << " is " << x << " " << #y << " is " << y << endl; #define show3(x,y,z) cerr << #x << " is " << x << " " << #y << " is " << y << " " << #z << " is " << z << endl; using namespace std; //using namespace __gnu_pbds; //#define ordered_set tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> //#define ordered_multiset tree<int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> typedef long long ll; typedef pair<ll, ll> pi; const ll INF = 1e16; static const int N = 200015; // We replicate the same structures from the “correct code.” // ========== Segment Tree for range-add, point-query ========== struct seg { // We store data in a 1D array tree[2*N]. // query(i): returns the sum from root to leaf i. // update(l, r, val): adds val to [l..r]. ll tree[2*N]; // Returns the prefix-sum-like query at index i. ll query(int i){ ll res = 0; for(i += N; i > 0; i >>= 1){ res += tree[i]; } return res; } // Add “x” to all elements in [l..r]. void update(int l, int r, ll x){ // 0-based => we store data from N..2N-1 in the leaves for(l += N, r += N+1; l < r; l >>= 1, r >>= 1){ if(l & 1) tree[l++] += x; if(r & 1) tree[--r] += x; } } }; // ========== Segment Tree for range-max query ========== struct segmax { ll tree[2*N]; // Returns max in [l..r]. ll query(int l, int r){ ll res = -INF; for(l += N, r += N+1; l < r; l >>= 1, r >>= 1){ if(l & 1) res = max(res, tree[l++]); if(r & 1) res = max(res, tree[--r]); } return res; } // Update position i with value x = max(tree[i], x). void update(int i, ll x){ for(i += N; i > 0; i >>= 1){ tree[i] = max(tree[i], x); } } }; // ========== Segment Tree for range-min query (storing (value, index)) ========== struct segmin { pi tree[2*N]; // (value, index) // Returns min in [l..r] by comparing .first pi query(int l, int r){ pi res = mp(INF, INF); for(l += N, r += N+1; l < r; l >>= 1, r >>= 1){ if(l & 1) { if(tree[l].f < res.f) res = tree[l]; l++; } if(r & 1) { --r; if(tree[r].f < res.f) res = tree[r]; } } return res; } // Update position i with x if x is “smaller” void update(int i, pi x){ for(i += N; i > 0; i >>= 1){ if(x.f < tree[i].f) tree[i] = x; } } }; // Query struct (same as correct code) struct query { ll U, id, mul; }; // Global arrays ll n, Q; ll X[N], B[N], Rpos[N]; // Rpos corresponds to R[i] in the correct code ll ans[N]; // For queries vector<query> queriesAt[N]; // For discretizing “U” vector<ll> dis; // Returns index in “dis” for upper_bound on i int getidx(ll i){ return (int)(upper_bound(all(dis), i) - dis.begin()); } // Our main data structures seg mAdd, cAdd; segmax finddie; segmin getmin; // ---------------------------- main ---------------------------- int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> Q; // Input for X[2..n+1] for(int i = 2; i <= n+1; i++){ cin >> X[i]; } // Input for B[1..n] for(int i = 1; i <= n; i++){ cin >> B[i]; } // Initialize // Clears the segment trees for(int i = 0; i < 2*N; i++){ mAdd.tree[i] = 0; cAdd.tree[i] = 0; finddie.tree[i] = -INF; getmin.tree[i] = mp(INF, INF); } // Build segmax for the “gap check” finddie // We do finddie.update(i-1, X[i]) for i=2..n+1 for(int i = 2; i <= n+1; i++){ finddie.update(i-1, X[i]); } // Build segmin for B[] so we can query min B in [s..t-1] // i in [1..n] for(int i = 1; i <= n; i++){ getmin.update(i, mp(B[i], i)); } // Build prefix sums in X[] for(int i = 2; i <= n+1; i++){ X[i] += X[i - 1]; } // Process queries for(int i = 1; i <= Q; i++){ int s, t, u; cin >> s >> t >> u; // If the max gap in [s..t-1] > u => ans[i] = -1 // Using segmax => finddie.query(s, t-1) if(finddie.query(s, t-1) > u) { ans[i] = -1; } else { // We'll add to queriesAt[s], queriesAt[somethingElse], etc. // queries[s].push_back({u, i, +1}); queriesAt[s].pb({(ll)u, (ll)i, +1LL}); // findpos = lower_bound(X+1, X+n+1, X[t] - u) - X; int findpos = (int)(lower_bound(X + 1, X + (n + 1), X[t] - u) - X); // Query segmin in [max(s, findpos) .. t-1] => get (BMin, indexMin) int leftBound = max(s, findpos); pi ret = getmin.query(leftBound, t - 1); ll tmiddle = ret.s; // the index with min B // queries[tmiddle].push_back({u, i, -1}); queriesAt[tmiddle].pb({(ll)u, (ll)i, -1LL}); // ans[i] += (X[t] - X[tmiddle]) * B[tmiddle] ans[i] += (X[t] - X[tmiddle]) * B[tmiddle]; // Also push “u” into dis dis.pb(u); } } // Now push INF to dis and do unique dis.pb(INF); discretize(dis); // We proceed with the stack-based logic // stack<int> st; B[n+1] = -inf; st.push(n+1); // The correct code sets B[n+1] = -INF as sentinel B[n+1] = -INF; stack<int> st; st.push(n+1); // We'll sweep from s=n down to 1 ll maxdis = 0; for(int s = n; s >= 1; s--){ // Keep track of maximum gap so far (not essential to the final logic, // but present in the code) maxdis = max(maxdis, X[s+1] - X[s]); // while(B[st.top()] >= B[s]) => pop while(!st.empty() && B[st.top()] >= B[s]){ int i = st.top(); st.pop(); // Use R[i] => which is Rpos[i] in our code // but we have NOT set Rpos[i] yet. We want the same approach as the original: // Actually, the original sets R[s] AFTER popping bigger B[] from the stack. // So for i, we do: // d1 = get( X[i] - X[s] ) // d2 = get( X[R[i]] - X[s] ) // mAdd.update(d1+1, d2, -B[i]) // cAdd.update(d1+1, d2, (X[i]-X[s])*B[i]) // cAdd.update(d2+1, N-1, (X[R[i]]-X[i]) * -B[i]) ll d1 = getidx(X[i] - X[s]); ll d2 = getidx(X[Rpos[i]] - X[s]); // update in [d1+1..d2] => -B[i] // note that “correct code” is 1-based for segment indexes, so we do the same mAdd.update(d1 + 1, d2, -B[i]); cAdd.update(d1 + 1, d2, (X[i] - X[s]) * B[i]); cAdd.update(d2 + 1, (int)dis.size() - 1, (X[Rpos[i]] - X[i]) * (-B[i])); } // Now st.top() is the next boundary int r = st.top(); Rpos[s] = r; // Then we do the “add the min(X[r] - X[s])” logic // D = get( X[r] - X[s] ) ll D = getidx(X[r] - X[s]); // Then update: // mAdd.update(1, D, B[s]) // cAdd.update(D+1, end, (X[r]-X[s])*B[s]) mAdd.update(1, D, B[s]); cAdd.update(D+1, (int)dis.size() - 1, (X[r] - X[s]) * B[s]); // push s st.push(s); // Now apply queries that start at s for(auto &q : queriesAt[s]){ ll uVal = q.U, qid = q.id, mulSign = q.mul; // get idx for uVal => disc ll idxU = getidx(uVal); // ans[qid] += mulSign * ( mAdd.query(idxU)*uVal + cAdd.query(idxU) ) ans[qid] += mulSign * ( mAdd.query(idxU)*uVal + cAdd.query(idxU) ); } } // Output final answers for(int i = 1; i <= Q; i++){ cout << ans[i] << endl; } 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...