正题
题目链接:https://jzoj.net/senior/#main/show/3236
题目大意
一个序列两个操作
- 1XY:1\ X\ Y:1 X Y:交换XXX和YYY两个数
- 2AB:2\ A\ B:2 A B:询问A∼BA\sim BA∼B这些数再序列中是否是连续的一段区间(不一定按顺序)
解题思路
先不考虑交换,对于询问我们发现它询问的区间不固定所以很难用线段树来做。所以我们可以用域值iii维护iii再目前序列的哪个位置。然后维护区间最大值和最小值,然后若询问B−AB-AB−A等于A∼BA\sim BA∼B这个区间的maxn−minnmaxn-minnmaxn−minn那么这些是一个连续区间。
然后交换我们定义segiseg_isegi表示在iii这个位置的数,然后就直接根据这个修改线段树然后交换。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=201000;
int n,m,id[N],seg[N],rea,rei;
struct Tree_node{int l,r,mins,maxs;
};
struct Seg_Tree{Tree_node t[N<<2];void Updata(int x,int ls,int rs){t[x].mins=min(t[ls].mins,t[rs].mins);t[x].maxs=max(t[ls].maxs,t[rs].maxs);return;}void Build(int x,int l,int r){t[x].l=l;t[x].r=r;if(l==r){t[x].mins=t[x].maxs=id[l];return;}int mid=(l+r)/2;Build(x*2,l,mid);Build(x*2+1,mid+1,r);Updata(x,x*2,x*2+1);}void Ask(int x,int l,int r){if(t[x].l==l&&t[x].r==r){Updata(0,0,x);return;}if(r<=t[x*2].r) Ask(x*2,l,r);else if(l>=t[x*2+1].l) Ask(x*2+1,l,r);else Ask(x*2,l,t[x*2].r),Ask(x*2+1,t[x*2+1].l,r);}void Change(int x,int pos,int z){if(t[x].l==t[x].r){t[x].mins=t[x].maxs=z;return;}if(pos<=t[x*2].r) Change(x*2,pos,z);else Change(x*2+1,pos,z);Updata(x,x*2,x*2+1);}
}Tree;
void Query(int l,int r)
{Tree.t[0].mins=n+1;Tree.t[0].maxs=0;Tree.Ask(1,l,r);rei=Tree.t[0].mins;rea=Tree.t[0].maxs;
}
void Swap(int x,int y)
{Query(x,x);int a1=rei;Query(y,y);int a2=rei;Tree.Change(1,x,a2);Tree.Change(1,y,a1);
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int x;scanf("%d",&x);id[x]=i;seg[i]=x;}Tree.Build(1,1,n);while(m--){int op,x,y;scanf("%d%d%d",&op,&x,&y);if(op==1){Swap(seg[x],seg[y]);swap(seg[x],seg[y]);}else{Query(x,y);if(rea-rei==y-x) printf("YES\n");else printf("NO\n");}}
}