ようこそ私Luoguスペース。
[タイトル]効果
そこ\(N- \)の高さ\([1、\ n]は \) と、キュー内の異なる人々 。
2つの動作モードがあります。
- 位置してみましょう\(X、\ yを用\)の場所を入れ替えます。
- 範囲指定された\([L、\ R&LT]を\)連続した配列か並ぶ高さ範囲内の誰に尋ねます。
二つの出力操作要求。
[説明]
セグメントツリー。
非常に簡単な操作。
操作IIの場合:
発明者らは、高\([L、\ R] \) のヒトコンセンサスの\(K =(R-L + 1)\) A。
私達はちょうどこの範囲の高さを見つける必要がある、との座標の人々の左端と右端に立っていました。
\((\)右座標- \(\)左座標\(+ 1)\)に等しい場合、値(k個の\)\、その\(k個の\)個人が単に連続配列を並びます。
それがより大きい場合、\(k個\)個人が他の人の数の間に挿入され、表示されたよりも小さくはあり得ません。
だから我々は、最大と最小の座標問い合わせをサポートする必要があります。
次のセグメントツリーのために背の高いターゲットを構築するために、座標、クエリ間隔の最大値と最小値の座標に対応する高さ値。
[コード]
// output format !!
// long long !!
#include <bits/stdc++.h>
#define H puts("HYX")
#define ls (x<<1)
#define rs (x<<1|1)
const int MAXN = 200000+10;
using std::max; using std::min; using std::swap;
struct TREE{int Max, Min;}t[MAXN*4];
int n, m, h[MAXN], loc[MAXN], L, R;
void build(int x, int l, int r){
if(l == r) return t[x].Max = t[x].Min = loc[l], void();
int mid = (l+r)>>1;
build(ls, l, mid), build(rs, mid+1, r);
t[x].Max = max(t[ls].Max, t[rs].Max);
t[x].Min = min(t[ls].Min, t[rs].Min);
}
void query(int x, int l, int r, int ql, int qr){
if(ql<=l && r<=qr){
L = min(L, t[x].Min);
R = max(R, t[x].Max);
return;
}
int mid = (l+r)>>1;
if(ql <= mid) query(ls, l, mid, ql, qr);
if(qr > mid) query(rs, mid+1, r, ql, qr);
}
void modify(int x, int l, int r, int p, int v){
if(l == r) return t[x].Max = t[x].Min = v, void();
int mid = (l+r)>>1;
if(p <= mid) modify(ls, l, mid, p, v);
else modify(rs, mid+1, r, p, v);
t[x].Max = max(t[ls].Max, t[rs].Max);
t[x].Min = min(t[ls].Min, t[rs].Min);
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; ++i) scanf("%d", h+i), loc[h[i]] = i;
build(1, 1, n);
while(m--){
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if(op == 1){
modify(1, 1, n, h[y], x);
modify(1, 1, n, h[x], y);
swap(h[x], h[y]), swap(loc[h[x]], loc[h[y]]);
}
else{
L = 1e9, R = 0;
query(1, 1, n, x, y);
if(R-L+1 == y-x+1) puts("YES");
else puts("NO");
}
}
return 0;
}