[jzoj 3236] 矮人排队 {权值线段树}

题目

Description
在七山七海之外的一个小村庄,白雪公主与N个矮人住在一起,所有时间都花在吃和玩League of Legend游戏。白雪公主决心终结这样的生活,所以为他们举办了体育课。 在每节课开始时,矮人必须按他们的身高站队。假定矮人们有高度1,2,…,N(每个人高度互不相同)。然而,由于不健康的生活方式,矮人的智力有所恶化,所以他们没有能力依照自己的高度排序。

因此,白雪公主发出以下形式命令帮助他们:

1 X Y:X和Y位置的矮人互换位置。

2 A B:询问高度为A,A+1,…, B的矮人(不一定是按照这个顺序)是否已形成了当前队列的连续子序列。

帮助矮人按照白雪公主的指示行动,并回答她的问题。

Input
输入的第一行包含两个正整数N和M,分别表示矮人的数量和白雪公主的命令数,2≤N≤200,000,2≤M≤200,000。

第二行包含N个用空格隔开的从1到N的正整数,每个数只出现一次,代表矮人的初始排列。

接下来的M行包含白雪公主的命令,形式为“1 X Y”(1≤X,Y≤N,X≠Y)或“2 A B”(1≤A≤B≤N)。

Output
对于每个命令2输出“YES”或“NO”。


解题思路

用两个线段树维护序列的最小值和最大值,显然 ( m a x − m i n ) = = ( y − x ) (max-min)==(y-x) (maxmin)==(yx)时有 Y E S YES YES


代码

#include<cstdio>
#include<algorithm>
using namespace std; 
const int N=200010; 
struct SegmentTree{
	int l,r,sum1,sum2; 
	#define l(x) tree[x].l 
	#define r(x) tree[x].r 
	#define sum1(x) tree[x].sum1
	#define sum2(x) tree[x].sum2
}tree[N*4];
int n,m,a[N],b[N]; 
void wh(int p){
	sum1(p)=min(sum1(p*2),sum1(p*2+1));
	sum2(p)=max(sum2(p*2),sum2(p*2+1));
}
void build(int p,int l,int r){
	l(p)=l,r(p)=r; 
	if (l==r) {sum1(p)=sum2(p)=b[l]; return;}
	int mid=(l+r)/2; 
	build(p*2,l,mid);
	build(p*2+1,mid+1,r); 
	wh(p); 
}
void change(int p,int k,int d){
	if (l(p)==r(p)){
		sum1(p)=sum2(p)=d; 
		return; 
	}
	int mid=(l(p)+r(p))/2; 
	if (k<=mid) change(p*2,k,d);
	if (k>mid) change(p*2+1,k,d); 
	wh(p); 
}
int ask1(int p,int l,int r){
	if (l<=l(p)&&r>=r(p)) return sum1(p); 
	int mid=(l(p)+r(p))/2; 
	if (r<=mid) return ask1(p*2,l,r); else 
	if (l>mid) return ask1(p*2+1,l,r); else 
	return min(ask1(p*2,l,mid),ask1(p*2+1,mid+1,r)); 
}
int ask2(int p,int l,int r){
	if (l<=l(p)&&r>=r(p)) return sum2(p); 
	int mid=(l(p)+r(p))/2; 
	if (r<=mid) return ask2(p*2,l,r); else 
	if (l>mid) return ask2(p*2+1,l,r); else 
	return max(ask2(p*2,l,mid),ask2(p*2+1,mid+1,r)); 
}
int main()
{
//	freopen("sa.txt","r",stdin); 
	scanf("%d%d",&n,&m); 
	for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[a[i]]=i; 
	build(1,1,n); 
	while (m--){
		int x,y,z,g,gg; 
		scanf("%d%d%d",&z,&x,&y); 
		if (z==1) {
			change(1,a[x],b[a[y]]); change(1,a[y],b[a[x]]); 
			g=b[a[y]]; b[a[y]]=b[a[x]]; b[a[x]]=g; 
			g=a[y]; a[y]=a[x]; a[x]=g; 
		} else {
			g=ask1(1,x,y),gg=ask2(1,x,y); 
			if ((gg-g)==(y-x)) printf("YES\n"); else printf("NO\n"); 
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值