题解:CF2138B Antiamuny Wants to Learn Swap
Engulf
·
·
题解
结论:f([l, r]) \neq g([l, r]) 的充要条件是:区间 [l, r] 存在 l \le i < j < k \le r \ \wedge \ a_i > a_j > a_k。
充分性:若区间 [l, r] 存在 l \le i < j < k \le r \ \wedge \ a_i > a_j > a_k,当交换相邻两项使得 j = i + 1, k = j + 1 的时候,因为要最小化 f,肯定会执行一次操作 2,直接交换 a_i 和 a_k,跳过 a_j,省下 1 次操作,所以 f([l, r]) \neq g([l, r])。
必要性:冒泡排序一个区间的操作数是恒定的,但 f([l, r]) \neq g([l, r]),说明 一定执行了操作 2。而操作 2 只有在 [a_{j - 1}, a_j, a_{j + 1}] \ \wedge \ a_{j - 1} > a_j > a_{j + 1} 的时候操作,才能比操作 1 省下 1 次,使得 f([l, r]) \neq g([l, r]),而又因为最多执行 1 次操作 2,所以 a_{j - 1} 和 a_{j + 1} 可以分别往前往后移动。于是区间 [l, r] 就会存在 l \le i < j < k \le r \ \wedge \ a_i > a_j > a_k。
充要条件可以归约问题。
问题转化为,q 次询问区间 [l, r] 是否存在 l \le i < j < k \le r \ \wedge \ a_i > a_j > a_k。
我们肯定希望 i, k 离 j 越近越好,这样可以覆盖到更多的询问。所以我们要求出:
这是经典问题,可以单调栈 \Theta(n) 求出。
现在,每个 j 可以对 l \le i < k \le r 的询问 [l, r] 贡献,就是对于每个询问,寻找是否存在 l \le i < k \le r,这是二维偏序问题,可以离线 + 树状数组解决。
:::success[实现]
```cpp line-numbers
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
#ifdef ONLINE_JUDGE
#define debug(...) 0
#else
#define debug(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#endif
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt;
cin >> tt;
while (tt--) {
int n, q; cin >> n >> q;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
stack<int> stk;
vector<int> lef(n, -1), rig(n, -1);
stk.emplace(0);
for (int i = 1; i < n; i++) {
while (stk.size() && a[stk.top()] < a[i]) stk.pop();
if (stk.size()) lef[i] = stk.top();
stk.emplace(i);
}
while (stk.size()) stk.pop();
stk.emplace(n - 1);
for (int i = n - 2; i >= 0; i--) {
while (stk.size() && a[stk.top()] > a[i]) stk.pop();
if (stk.size()) rig[i] = stk.top();
stk.emplace(i);
}
vector<int> vec(n);
using natsu = tuple<int, int, int, int>;
vector<natsu> que;
for (int i = 1; i < n - 1; i++) {
if (lef[i] < 0 || rig[i] < 0) continue;
lef[i]++, rig[i]++;
que.emplace_back(lef[i], rig[i], 0, 0);
}
vector<int> ans(q);
for (int i = 0; i < q; i++) {
int l, r; cin >> l >> r;
que.emplace_back(l, r, i, 1);
}
sort(que.begin(), que.end(), [](natsu x, natsu y) {return get<0>(x) != get<0>(y) ? get<0>(x) > get<0>(y) : get<3>(x) < get<3>(y);});
vector<int> bit(n + 1);
for (auto [l, r, id, op]: que) {
if (op == 0) for (; r <= n; r += r & -r) bit[r]++;
else for (; r; r -= r & -r) ans[id] |= bit[r];
}
for (int i = 0; i < q; i++)
cout << (ans[i] ? "NO\n" : "YES\n");
}
return 0;
}
```
:::