A.
B.1-n的全排列,两个操作:1、(1,a,b)交换位置a和位置b上的数。2、(2,a,b)查询a.a+1…b是否可以组成一个连续序列,可以不按照升序,例如:a.a+2,a+1,在(2,a,a+2)时,ans=YES.(n<=200000)
其实可以算一眼线段树吧= =
线段树区间[a,b]维护mn,mx,[a,b]在序列里最左边最右边的值。单点修改,查询。此题丧病卡常数。话说第一次遇见卡常数的题。。。不过想想,以前写的seg都是代码少,常数大的。。。好像确实该改改了。。。(tle第一次才55= =
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 200005
#define pa pair<int,int>
#define mp make_pair
#define inf 0x7fffffff
using namespace std;
struct seg{
int l,r,mx,mn;
}t[N*4];
int v[N],pos[N],n,m,mn,mx;
void build(int k,int l,int r){
t[k].l=l;t[k].r=r;
if(l==r){
t[k].mx=pos[l];
t[k].mn=pos[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
t[k].mn=min(t[k<<1].mn,t[k<<1|1].mn);
}
void modify(int k,int a,int x){//pos[a]->x
if(t[k].r<a||a<t[k].l) return;
if(t[k].l==a&&t[k].r==a){
t[k].mx=x;t[k].mn=x;
return;
}
int mid=(t[k].l+t[k].r)>>1;
if(a<=mid) modify(k<<1,a,x);
if(a>mid) modify(k<<1|1,a,x);
t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
t[k].mn=min(t[k<<1].mn,t[k<<1|1].mn);
}
void query(int k,int a,int b){
if(t[k].r<a||b<t[k].l) return;
if(a<=t[k].l&&t[k].r<=b) {
mx=max(mx,t[k].mx);
mn=min(mn,t[k].mn);
return;
}
int mid=(t[k].l+t[k].r)>>1;
if(b<=mid) {query(k<<1,a,b);return;}
if(a>mid) {query(k<<1|1,a,b);return;}
query(k<<1,a,b);query(k<<1|1,a,b);
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) //pos[x]=i 身高为x位于i
scanf("%d",&v[i]),pos[v[i]]=i; //v[x]=i 位于x身高i
build(1,1,n);
for(int i=1;i<=m;i++){
int o,a,b;
scanf("%d%d%d",&o,&a,&b);
if(o==1){
modify(1,v[a],pos[v[b]]);
modify(1,v[b],pos[v[a]]);
swap(pos[v[a]],pos[v[b]]);
swap(v[a],v[b]);
}
if(o==2){
mx=0;mn=inf;
query(1,a,b);
if(mx-mn==b-a) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
C.