5882. 【NOIP2018模拟A组9.25】雪人(线段树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/82864898

题目大意:

给定一个长度为 N 的序列,每次操作可以选选择一个数,这个数和它右边的数比大小,如 果这个数比较大,就和右边的数交换,然后和右边的数接着比大小直到某一次它右边的数比 他大或者他右边没有数了。求最小的操作次数使得序列变为升序。

思路:

因为交换是不会改变相对顺序的,所以从左往右找,找到一个数右边有比他大的就要答案加一。

程序:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 1000005
using namespace std;

struct tree{int a;}t[N*8];
int n,ans;
int a[N];
bool find(int rt,int l,int r,int x,int y){
	if (l==x&&r==y)	return t[rt].a;

	int mid=(l+r)/2;
	if (mid<x) return find(rt*2+1,mid+1,r,x,y);
	else if (mid>=y) return find(rt*2,l,mid,x,y);
	else return find(rt*2+1,mid+1,r,mid+1,y)&find(rt*2,l,mid,x,mid);
}

void insert(int rt,int l,int r,int x){
	if (l==r){
		t[rt].a=1;
		return;
	}
	int mid=(l+r)/2;
	if (x<=mid) insert(rt*2,l,mid,x);
			else insert(rt*2+1,mid+1,r,x);
	t[rt].a=t[rt*2].a&t[rt*2+1].a;
}

int main(){
	freopen("snowman.in","r",stdin);
	freopen("snowman.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		if (a[i]!=1) if (!find(1,1,n,1,a[i]-1)) ans++;
		insert(1,1,n,a[i]);
	}
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/qq872425710/article/details/82864898
今日推荐