#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4e5; // twice the contraints (since we duplicate intervals in modifyIntervals())
const int MAXK = 21; // ~log(MAXN), for binary lifting
long long n, m;
long long s[MAXN], e[MAXN];
int nextBest[MAXN]; // precalculated next best interval
int lift[MAXN][MAXK]; // precalculated binary lifting. lift[i][k] is taking 2^k intervals, starting from i-th one
void readInput() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> s[i] >> e[i];
}
}
void removeUnnecessaryIntervals() {
// interval is unnecessary if it is covered fully by other intervals
int cnt = 0;
// sort the intervals
vector<pair<long long, long long>> intervals;
for (int i = 0; i < n; i++)
intervals.push_back({s[i], -e[i]}); // this will help sort by increasing s[i],
// and then by decreasing e[i]
sort(intervals.begin(), intervals.end());
long long furthestEnd = -1;
for (auto interval : intervals) {
long long start = interval.first;
long long end = -interval.second;
if (end <= furthestEnd) {
continue; // this interval is unnecessary
}
furthestEnd = end;
s[cnt] = start;
e[cnt] = end;
cnt++;
}
n = cnt; // update interval count
}
void modifyIntervals() {
// to make implementation a bit easier
// deal with the cases of s > e
for (int i = 0; i < n; i++) {
if (s[i] > e[i]) e[i] += m;
}
// duplicate all intervals: (s, e) -> (s+m, e+m)
for (int i = 0; i < n; i++) {
s[i+n] = s[i] + m;
e[i+n] = e[i] + m;
}
n *= 2; // since we duplicated
removeUnnecessaryIntervals(); // remove covered fully by other intervals
}
void precalcNexts() {
// sort intervals by their starts
vector<pair<long long, int>> intervals; // vector of pairs {start, id}
for (int i = 0; i < n; i++)
intervals.push_back({s[i], i});
sort(intervals.begin(), intervals.end());
// calculate nexts with two pointers technique
int i = 0;
for (auto interval : intervals) {
int id = interval.second;
while (i < n) {
int intervalId = intervals[i].second;
if (s[intervalId] > e[id]) // not overlapping
break;
i++;
}
nextBest[id] = intervals[i - 1].second;
}
}
void precalcBinaryLifting() {
for (int i = 0; i < n; i++)
lift[i][0] = nextBest[i];
for (int k = 1; k < MAXK; k++) for (int i = 0; i < n; i++)
lift[i][k] = lift[ lift[i][k-1] ][k-1];
}
int tryFrom(int startAdmin) {
long long startTime = s[startAdmin];
// do binary lifting (binary search) to find the furthest reachable admin
// such that it would still not cover full circle
int cntJumps = 0;
int curAdmin = startAdmin;
for (int i = MAXK-1; i >= 0; i--) {
int jumpedToId = lift[curAdmin][i];
if (e[jumpedToId] < (startTime + m)) { // does not cover full circle
cntJumps += (1<<i); // 2^i
curAdmin = jumpedToId;
}
}
// we found the last before we get to full circle
cntJumps++;
curAdmin = lift[curAdmin][0];
if (e[curAdmin] < (startTime + m)) {
return -1; // impossible since we did not cover full circle
}
return cntJumps + 1;
}
int main() {
readInput();
modifyIntervals(); // see the explanation at the top
precalcNexts();
precalcBinaryLifting();
int ans = -1;
for (int i = 0; i < n; i++) {
int curTaken = tryFrom(i);
// update ans
if (curTaken == -1) continue;
if (ans == -1 || curTaken < ans) ans = curTaken;
}
cout << ans << endl;
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |