题意
给出
N
N
N个人的身高,有两种操作:
1
、
1、
1、交换两人位置。
2
、
2、
2、查询
a
∼
b
a\sim b
a∼b这些身高的人在序列中是否是一个连续子序列。
思路
一开始我用线段树记录当前区间的最大值和最小值,然后查询时就把在 a ∼ b a\sim b a∼b的区间拿出来,暴力判断一下是否连续,事实证明我是 ∗ ∗ ** ∗∗。
其实要用线段树维护高度为 i i i的人位置在哪,以及区间最大最小值,在查询时,我们利用线段树判断一下当前区间最大位置-最小位置是否等于查询的人的总数。
代码
#include<cstdio>
#include<algorithm>
struct SegmentTree {
int l, r, mins, maxs;
}t[800001];
int n, m, f;
int a[200001], h[200001];
void build(int p, int l, int r) {
t[p].l = l;
t[p].r = r;
if (l == r) {
t[p].mins = t[p].maxs = h[l];
return;
}
int mid = l + r >> 1;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
t[p].mins = std::min(t[p * 2].mins, t[p * 2 + 1].mins);
t[p].maxs = std::max(t[p * 2].maxs, t[p * 2 + 1].maxs);
}
void change(int p, int pos, int v) {
if (t[p].l == t[p].r) {
t[p].mins = t[p].maxs = v;
return;
}
int mid = t[p].l + t[p].r >> 1;
if (pos <= mid) change(p * 2, pos, v);
else change(p * 2 + 1, pos, v);
t[p].mins = std::min(t[p * 2].mins, t[p * 2 + 1].mins);
t[p].maxs = std::max(t[p * 2].maxs, t[p * 2 + 1].maxs);
}
std::pair<int, int> ask(int p, int l, int r) {
if (l <= t[p].l && t[p].r <= r) return std::make_pair(t[p].mins, t[p].maxs);
int mid = t[p].l + t[p].r >> 1;
std::pair<int, int> res, res1, res2;
if (l <= mid) res1 = ask(p * 2, l, r), res = res1;
if (r > mid) res2 = ask(p * 2 + 1, l, r), res = l <= mid ? std::make_pair(std::min(res1.first, res2.first), std::max(res1.second, res2.second)) : res2;
return res;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), h[a[i]] = i;
build(1, 1, n);
for (int op, x, y; m; m--) {
scanf("%d %d %d", &op, &x, &y);
if (op == 1) {
change(1, a[x], h[a[y]]);
change(1, a[y], h[a[x]]);
std::swap(a[x], a[y]);
std::swap(h[a[x]], h[a[y]]);
}
else {
std::pair<int, int> res = ask(1, x, y);
res.second - res.first == y - x ? printf("YES\n") : printf("NO\n");
}
}
}