题意:
up为交换两个位置上的人,query为询问以这两个位置为左右边界的区域上的人的编号是不是连在一起,354就是在一起。
解析:
因为所以人编号不同,所以只要求出区域内的最大值减去最小值+1是不是等于区域长度即可。用线段树维护最大值和最小值。
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 200009
#define rs rt<<1|1
#define ls rt<<1
using namespace std;
struct tree{
int low,big;
}tr[4*N];
int nu[N];
int n,q;
void build(int l,int r,int rt){
if(l==r){
tr[rt].low=tr[rt].big=l;return;
}
int mid=l+r>>1;
build(l,mid,ls);
build(mid+1,r,rs);
tr[rt].low=min(tr[ls].low,tr[rs].low);
tr[rt].big=max(tr[ls].big,tr[rs].big);
}
void update(int l,int r,int rt,int f,int pos){
if(l==r){
tr[rt].low=tr[rt].big=f;return;
}
int mid=l+r>>1;
if(pos<=mid)update(l,mid,ls,f,pos);
else update(mid+1,r,rs,f,pos);
tr[rt].low=min(tr[ls].low,tr[rs].low);
tr[rt].big=max(tr[ls].big,tr[rs].big);
}
int Query_max(int l,int r,int rt,int x,int y){
if(y>=r&&x<=l)return tr[rt].big;
//为什么是小于等于?查询4~8时,实际上参照段是4~5,6~8,在查询区间内部
int mid=l+r>>1;
if(mid>=y)return Query_max(l,mid,ls,x,y);
if(mid<x)return Query_max(mid+1,r,rs,x,y);
return max(Query_max(l,mid,ls,x,y),Query_max(mid+1,r,rs,x,y));
}
int Query_min(int l,int r,int rt,int x,int y){
if(y>=r&&x<=l)return tr[rt].low;
int mid=l+r>>1;
if(mid>=y)return Query_min(l,mid,ls,x,y);
if(mid<x)return Query_min(mid+1,r,rs,x,y);
return min(Query_min(l,mid,ls,x,y),Query_min(mid+1,r,rs,x,y));
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)nu[i]=i;//nu[1]==2表示第一个位置上的人编号为2
build(1,n,1);
for(int i=1;i<=q;i++){
int f,a,b;scanf("%d%d%d",&f,&a,&b);
if(f==1){
update(1,n,1,nu[a],b);//b位置改成nu[a]
update(1,n,1,nu[b],a);
swap(nu[a],nu[b]);
}
else{
if(Query_max(1,n,1,a,b)-Query_min(1,n,1,a,b)==b-a)
printf("YES\n");
else
printf("NO\n");
}
}
}
//1 10
//3 7
//1 5 6 10
//3 5 6 8