AcWing 1215 小朋友排队 题解(蓝桥杯 树状数组)

原题
冒泡排序+逆序对,想出考虑计算高于/低于每个身高的人数,利用树状数组进行人数修改

#include<bits/stdc++.h>

using namespace std;

#define int long long 

const int N = 1e6 + 10;

int h[N], tr[N];
int n;
int sum[N];
int ans;

int lowbit(int x){
	return x & -x;
}

void add(int a, int v){
	for(int i = a; i < N; i += lowbit(i)){
		tr[i] += v;
	}
}

int query(int x){
	int rex = 0;
	for(int i = x; i ; i -= lowbit(i)){
		rex += tr[i];
	}
	return rex;
}

signed main()
{
	cin>>n;
	
	for(int i = 0; i < n; i ++ ) cin>>h[i], h[i] ++ ;//小朋友的身高可能是0,下列存在query(h[i]-1),会造成溢出,所以让所有数据+1 
	
	for(int i = 0; i < n; i ++ ){
		sum[i] = query(N - 1) - query(h[i]);//找出身高高于这个小朋友h[i]的小朋友的个数
		add(h[i], 1);//这个身高的小朋友数量+1 
	}
	
	memset(tr, 0, sizeof tr);//重新计算身高低于这个小朋友的人数,要把树状数组清空
	
	for(int i = n - 1; i >= 0; i -- ){
		sum[i] += query(h[i] - 1);//加上低于这个身高的人数 
		add(h[i], 1);
	} 
	
	//sum[i]记录的是比这个小朋友身高高的和低的总和
	//对于每一个比他高的/比他低的他都会被交换一次,所以假设有3个比他高的,2个比他低的
	//那么他的不高兴次数应该是1+2+3+4+5,因为第i次交换会使小朋友的不高兴程度+i 
	for(int i = 0; i < n; i ++ ) ans += sum[i] * (sum[i] + 1) / 2;
	
	cout<<ans<<endl;
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值