#牛客春招刷题训练营# + 链接
想了半天最终决定还是暴力
题目没有保证输入不重复,先判重,重了肯定不能单调
然后遍历抽出哪一段,不在该段的全都插到平衡树里面,移动时只需要插一个数删一个数,单次复杂度O(logn)
每次遍历在平衡树中查询(最小数)和(最大数+1)的序号,如果相等则说明当前这段可以插入到排序后的数组里
另外,对于遍历的段,需要保证它本身是单调的,这个用简单计数器维护一下就可以了,具体可以看代码
#include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> int a[200010]; using namespace __gnu_pbds; tree<int, null_type, std::less<int>, rb_tree_tag, tree_order_statistics_node_update> tr; int main() { int T,n,m; scanf("%d", &T); while (T--) { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%d", a+i); } std::unordered_set<int> st; bool bad=false; for (int i=1;i<=n;i++) { if (!st.insert(a[i]).second) { bad=true; break; } } if (bad) { puts("NO"); continue; } for (int i=n;i>m;i--) { tr.insert(a[i]); } // 单增=up, 单减=down int cntu = 0, cntd = 0; bool good = false; for (int i=2;i<m;i++) { if (a[i] <= a[i-1]) ++cntu; if (a[i] >= a[i-1]) ++cntd; } for (int i=m;i<=n;i++) { if (a[i] <= a[i-1]) ++cntu; if (a[i] >= a[i-1]) ++cntd; if (cntu==0) { // 验证单增 if (tr.order_of_key(a[i-m+1]) == tr.order_of_key(a[i]+1)) { good = true; break; } } if (cntd==0) { // 验证单减 if (tr.order_of_key(a[i]) == tr.order_of_key(a[i-m+1]+1)) { good = true; break; } } if (i<n) { if (a[i-m+2] <= a[i-m+1]) --cntu; if (a[i-m+2] >= a[i-m+1]) --cntd; tr.erase(a[i+1]); tr.insert(a[i-m+1]); } } if (good) puts("YES"); else puts("NO"); tr.clear(); } return 0; }