【gmoj】【线段树】矮人排队

【gmoj】【线段树】矮人排队

题目

P3236


解题思路

暴力想法就是判断编号A~B的小矮人位置最大值减最小值是否等于B-A
但是时间复杂度达到O(NM)
想到查询位置时可以用线段树优化一丢丢长


代码

暴力

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,x,l,r,a[200010],w[200010];
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		w[a[i]]=i;
	}
	while (m--)
	{
		  scanf("%d%d%d",&x,&l,&r);
		  if (x==1)
		  {
		  	 swap(w[a[l]],w[a[r]]);
		  	 swap(a[l],a[r]);
		  } 
		  else {
		  	  int mi=1e9,ma=0;
		  	  for (int i=l;i<=r;i++)
		  	      mi=min(mi,w[i]),ma=max(ma,w[i]);
		  	  if (ma-mi==r-l) printf("YES\n");
				 else printf("NO\n"); 
		  }
	}
	return 0;
}

正解

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath> 
using namespace std;
int n,m,x,y,z,d1,d2;
int a[200010],w[200010],ma[1000100],mi[1000010];
void build(int l,int r,int k)
{
	 if (l==r)
	 {
	 	ma[k]=mi[k]=w[l];
	 	return;
	 }
	 int mid=(l+r)/2;
	 build(l,mid,k*2);
	 build(mid+1,r,k*2+1);
	 ma[k]=max(ma[k*2],ma[k*2+1]);
	 mi[k]=min(mi[k*2],mi[k*2+1]);
}
void change(int l,int r,int k,int q)
{
	 if (l==r)
	 {
	 	ma[k]=mi[k]=w[l]; 
	 	return;
	 }
	 int mid=(l+r)/2;
	 if (q<=mid) change(l,mid,k*2,q);
	    else change(mid+1,r,k*2+1,q);
	 ma[k]=max(ma[k*2],ma[k*2+1]);
	 mi[k]=min(mi[k*2],mi[k*2+1]);
}
int ask1(int x,int y,int l,int r,int k)
{ 
	 if (x<=l&&y>=r) return ma[k];
	 int mid=(l+r)/2,da=0;
	 if (x<=mid) da=ask1(x,y,l,mid,k*2);
	 if (y>mid) da=max(da,ask1(x,y,mid+1,r,k*2+1));  
	 return da; 
}
int ask2(int x,int y,int l,int r,int k)
{ 
	 if (x<=l&&y>=r) return mi[k];
	 int mid=(l+r)/2,da=1e9;
	 if (x<=mid) da=ask2(x,y,l,mid,k*2);
	 if (y>mid) da=min(da,ask2(x,y,mid+1,r,k*2+1)); 
	 return da;
}
int main()
{
	memset(mi,0x7f,sizeof(mi));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		w[a[i]]=i;
	}
	build(1,n,1);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&z,&x,&y);
		if (z==1)
		{
			swap(a[x],a[y]);
			w[a[x]]=x,w[a[y]]=y;
			change(1,n,1,a[x]);
			change(1,n,1,a[y]);
		}
		else {  
			   d1=ask1(x,y,1,n,1),d2=ask2(x,y,1,n,1);
			   if (d1-d2==y-x)
			      printf("YES\n");
			      else printf("NO\n");
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值