Submission #291424

#TimeUsernameProblemLanguageResultExecution timeMemory
291424rama_pangArranging Tickets (JOI17_arranging_tickets)C++14
100 / 100
2168 ms15832 KiB
#include <bits/stdc++.h> using namespace std; // Solution: // We can binary search the answer. We also break the circle to // a line segment. // // If intervals [a, b] and [c, d] is reversed, and a < b < c < d, // then we originally have interval values: // ([1, a), 0), ([a, b], 1), ((b, c), 0), ([c, d], 1), ((d, N], 0) // and reversed values are: // ([1, a), 2), ([a, b], 1), ((b, c), 2), ([c, d], 1), ((d, N], 2) // We can see that all regions increased - thus all flipped intervals // must share a point t. // // For a fixed point t, let a[i] be the sum of people travelling through i, // and b[i] be the final one once we reversed optimally. Then b[t] = max(b[i]) // or b[t] = max(b[i]) - 1. This allows us to check only a[t] - max_ans and // a[t] - max_ans + 1 flips for a point t, where max_ans is the current // mid in the binary search. Proof follows. // // Assume then b[t] < max(b[i]) - 1. Then we can find two reversed segments [a, b] and // [c, d], such that a is the minimum coordinate of reversed segment and d is the // maximum one of reversed segments. By definition, [a, b] and [c, d] passes through t, // and we can unreverse them. This will not change max(b[i]), and increment b[t] by either // 1 or 2. Thus we can keep doing this until the condition is satisfied without breaking // the solution. // // This yields an O(M^2 log^2 M) solution. We can further speed this up by noticing that // we only need to check t where a[t] = max(a[i]) and t is the minimum and maximum i that // is equal max(a[i]). Why? Since b[i] - a[i] is smaller the closer i is to t, let j not be // in the common interval of all reversed intervals. Then b[t] - a[t] + 1 <= b[j] - a[j]. // If we assume a[t] + 1 <= a[j], we can sum them to get b[t] + 2 <= b[j]. But by definition // b[t] = max(b[i]) or b[t] = max(b[i]) - 1, thus we get a contradiction. Therefore, a[t] = // max(a[i]) must be satisfied. // // Now we prove the second condition (only checking the leftmost and rightmost t such that a[t] = // max(a[i])). First, there is no reversed interval [x, y], such that l < x < y < r. Assume otherwise. // Then, when we reverse [x, y], let b' be the resulting arrangement. We have b'[t] = b[t] + 1 // and b'[l] = b[l] - 1, and b'[l] >= b'[t] since we use t = l. Then we get b[l] >= b[t] + 2 which // is a contradiction since b[t] = max(b[i]) or b[t] = max(b[i]) - 1. Thus no such [x, y] exist, which // means we only need to consider t = l or t = r. // // After we determine max_ans and t, we can do the reversal greedily. We can use a segment tree or a // priority queue to support the operations: point update += x at position i and remove x items from // the right to simulate the greedy selection. We check after we do all flips to see if we satisfy // everything. // // Time: O(N log^2 N) int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int N, M; cin >> N >> M; vector<int> A(M), B(M), C(M); for (int i = 0; i < M; i++) { cin >> A[i] >> B[i] >> C[i]; A[i]--, B[i]--; if (A[i] > B[i]) { swap(A[i], B[i]); } } vector<long long> sum(N); vector<vector<pair<int, int>>> segs(N); for (int i = 0; i < M; i++) { sum[A[i]] += C[i]; sum[B[i]] -= C[i]; segs[A[i]].emplace_back(B[i], C[i]); } for (int i = 1; i < N; i++) { sum[i] += sum[i - 1]; } long long mx = *max_element(begin(sum), end(sum)); int ll = -1, rr = -1; for (int i = 0; i < N; i++) { if (sum[i] == mx) { ll = i; break; } } for (int i = N - 1; i >= 0; i--) { if (sum[i] == mx) { rr = i; break; } } auto Check = [&](int t, long long mx, long long flips) -> bool { vector<long long> upd_sum(N); for (int i = 1; i < N; i++) { upd_sum[i] += upd_sum[i - 1]; } long long flipped = 0; priority_queue<array<int, 3>> pq; for (int pos = 0; pos <= t; pos++) { for (auto i : segs[pos]) { if (i.first > t) { pq.push({i.first, pos, i.second}); } } // Look at effects to upd_sum for derivation, sum[pos] += 2 * constant long long need = (sum[pos] - mx + flips + 1) / 2; if (pos == t) need = flips; need = max(need - flipped, 0ll); flipped += need; while (need > 0) { if (pq.empty()) { return false; } auto arr = pq.top(); pq.pop(); long long del = min(need, 1ll * arr[2]); arr[2] -= del, need -= del; if (arr[2] > 0) { pq.push(arr); } // Add [0, A) and [B, N) upd_sum[0] += del; upd_sum[arr[1]] -= del; upd_sum[arr[0]] += del; // Undo [A, B) upd_sum[arr[1]] -= del; upd_sum[arr[0]] += del; } } for (int i = 0; i < N; i++) { if (i > 0) { upd_sum[i] += upd_sum[i - 1]; } if (sum[i] + upd_sum[i] > mx) { return false; } } return true; }; auto CheckAll = [&](long long m) -> bool { return Check(ll, m, sum[ll] - m + 0) || Check(ll, m, sum[ll] - m + 1) || Check(rr, m, sum[rr] - m + 0) || Check(rr, m, sum[rr] - m + 1); }; long long lo = 0, hi = mx; while (lo < hi) { long long md = (lo + hi) / 2; if (CheckAll(md)) { hi = md; } else { lo = md + 1; } } cout << lo << "\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...