jzoj3462. 【NOIP2013模拟联考5】休息(rest) 树状数组逆序对

Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits

Description

休息的时候,可以放松放松浑身的肌肉,打扫打扫卫生,感觉很舒服。在某一天,某LMZ 开始整理他那书架。已知他的书有n 本,从左到右按顺序排列。他想把书从矮到高排好序,而每一本书都有一个独一无二的高度Hi。他排序的方法是:每一次将所有的书划分为尽量少的连续部分,使得每一部分的书的高度都是单调下降,然后将其中所有不少于2 本书的区间全部翻转。重复执行以上操作,最后使得书的高度全部单调上升。可是毕竟是休息时间,LMZ 不想花太多时间在给书排序这种事上面。因此他划分并翻转完第一次书之后,他想计算,他一共执行了多少次翻转操作才能把所有的书排好序。LMZ 惊奇地发现,第一次排序之前,他第一次划分出来的所有区间的长度都是偶数。

Input

第一行一个正整数n, 为书的总数。

接下来一行n个数,第i个正整数Hi,为第i 本书的高度。

Output

仅一个整数,为LMZ 需要做的翻转操作的次数。

Sample Input

6

5 3 2 1 6 4

Sample Output

3

【样例解释】

第一次划分之后,翻转(5,3,2,1),(6,4)。之后,书的高度为1 2 3 5 4 6,然后便是翻转(5,4)即可。

Data Constraint
对于10%的数据:n<=50

对于40%的数据:n<=3000

对于100%的数据:1<=n<=100000, 1<=Hi<=n

解法:树状数组求逆序对

  • 我们只需要先把这个数列排一次序之后求出逆序对即可,注意开long long

AC代码

#include<cstdio>
#include<algorithm>
#define ll long long
#define re register ll
using namespace std;
ll n,ans,a[100010],c[100010];
inline ll read() {
	ll x=0,cf=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {
		if(ch=='-') cf=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*cf;
}
inline void add(ll x,ll y) {
	for(;x<=n;x+=x&-x) c[x]+=y;
}
inline ll query(ll x) {
	ll res=0;
	for(;x;x-=x&-x) res+=c[x];
	return res;
}
int main() {
	n=read();
	for(re i=1;i<=n;i++) {
		a[i]=read();
	}
	ll l=1,r=1;
	for(re i=2;i<=n;i++) {
		if(a[i]<a[i-1]) r=i;
		else {
			if(l==r) continue;
			sort(a+l,a+r+1);
			ans++,l=i,r=i;
		}
	}
	if(l!=r) {
		ans++;
		sort(a+l,a+r+1);
	}
	for(re i=1;i<=n;i++) {
		add(a[i],1);
		ans+=i-query(a[i]);
	}
	printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值