Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
With only adjacent swaps, the minimum cost is the inversion count. So operation 2 helps only if one move can remove more inversion-count “debt” than one adjacent swap would.
Look at what operation 2 does to three consecutive elements . It turns them into . The only time this reduces the inversion count by is when .
If operation 2 only removes inversion, it costs operation and saves nothing. To get , operation 2 must be used on a decreasing consecutive triple at that moment.
A decreasing consecutive triple can be created using only useful adjacent swaps iff the original subarray already contains a decreasing subsequence of length : indices with .
For every middle index , find the nearest previous index with a larger value and the nearest next index with a smaller value. This gives the shortest interval containing a decreasing triple centered at . A query is NO iff one of these intervals lies fully inside it.
For any array , sorting with only adjacent swaps costs exactly the number of inversions. Call this number .
So . The only question is whether the one allowed distance- swap can make the total cost strictly smaller than .
What operation 2 can actually save
Suppose the current three consecutive elements are
Operation 2 changes this into
Only the relative order of these three elements changes. Since all values are distinct, there are only a few cases:
An adjacent swap that helps removes exactly inversion and costs operation. So if operation 2 removes only inversion, congrats, you did nothing special. Same cost, same progress. Very mid.
To get , operation 2 must remove inversions in one operation. Therefore, right before using it, the current array must contain three consecutive elements in strictly decreasing order.
Also, every adjacent swap used before that must be a helpful swap. If you ever swap an already-correct adjacent pair, you add an inversion, and the one special move cannot make the whole route cheaper than .
So the useful scenario is exactly:
The key characterization
A subarray is not perfect iff it contains a decreasing subsequence of length .
That means there exist indices
such that
Why?
If such a triple exists, we can use adjacent swaps that only reduce inversions to bring these three values together as a consecutive decreasing triple. Elements bigger than can be pushed to the right, elements smaller than can be pushed to the left, and extra elements between their values can be crossed by until only one middle value remains. Every one of those swaps is an inverted adjacent pair, so no wasted moves.
Then operation 2 changes
removing inversions for the price of operation. After that, finish sorting with normal adjacent swaps. Total cost becomes , so the subarray is definitely not perfect.
For the other direction, suppose the subarray is not perfect. Then operation 2 must have removed inversions, so it was applied to a consecutive decreasing triple . Since all previous adjacent swaps must have only removed inversions, they never create a new inverted pair; they only delete existing ones. Therefore were already pairwise inverted in the original subarray, meaning they formed a decreasing subsequence of length .
So the whole problem becomes:
For each query , does contain a pattern?
Turning triples into intervals
For every index , treat it as the middle of the decreasing triple. We need:
Define:
If both exist, then
so contains a decreasing triple.
Even better: this nearest choice is enough for all queries. If a query contains any decreasing triple centered at , then its left endpoint is at most some valid previous greater index, so it is also at most because is the nearest one. Similarly, its right endpoint is at least because is the nearest next smaller.
So query is bad iff there exists some such that
Answering queries fast
For every valid interval , store:
Then prefix-max it:
Now is the largest left endpoint among all bad intervals ending at or before .
For query :
NO;YES.We compute and with monotonic stacks:
Total complexity per test case is
which is exactly what we want when the input size is big enough to bully lazy solutions.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, q;
cin >> n >> q;
vector<int> a(n + 2);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<int> leftGreater(n + 2, 0), rightSmaller(n + 2, n + 1), st;
for (int i = 1; i <= n; i++) {
while (!st.empty() && a[st.back()] < a[i]) st.pop_back();
if (!st.empty()) leftGreater[i] = st.back();
st.push_back(i);
}
st.clear();
for (int i = n; i >= 1; i--) {
while (!st.empty() && a[st.back()] > a[i]) st.pop_back();
if (!st.empty()) rightSmaller[i] = st.back();
st.push_back(i);
}
vector<int> best(n + 2, 0);
for (int j = 1; j <= n; j++) {
int l = leftGreater[j], r = rightSmaller[j];
if (l > 0 && r <= n) best[r] = max(best[r], l);
}
for (int i = 1; i <= n; i++) {
best[i] = max(best[i], best[i - 1]);
}
while (q--) {
int l, r;
cin >> l >> r;
cout << (best[r] >= l ? "NO\n" : "YES\n");
}
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, q;
cin >> n >> q;
vector<int> a(n + 2);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<int> leftGreater(n + 2, 0), rightSmaller(n + 2, n + 1), st;
for (int i = 1; i <= n; i++) {
while (!st.empty() && a[st.back()] < a[i]) st.pop_back();
if (!st.empty()) leftGreater[i] = st.back();
st.push_back(i);
}
st.clear();
for (int i = n; i >= 1; i--) {
while (!st.empty() && a[st.back()] > a[i]) st.pop_back();
if (!st.empty()) rightSmaller[i] = st.back();
st.push_back(i);
}
vector<int> best(n + 2, 0);
for (int j = 1; j <= n; j++) {
int l = leftGreater[j], r = rightSmaller[j];
if (l > 0 && r <= n) best[r] = max(best[r], l);
}
for (int i = 1; i <= n; i++) {
best[i] = max(best[i], best[i - 1]);
}
while (q--) {
int l, r;
cin >> l >> r;
cout << (best[r] >= l ? "NO\n" : "YES\n");
}
}
return 0;
}