HDU 1394 Minimum Inversion Number Segment Tree解法

本题有两个考点:

1 求逆序数的性质

计算逆序数的公式, 一个数arr[i]从前面放到后面,必然会有n-arr[i]-1个数比这个大,那么就有n-arr[i]-1个逆序数增加,同时因为前面少了个arr[i]数,那么就必然有arr[i]个(加上零)数比起小的数失去一个逆序数,总共失去arr[i]个逆序数,所以新的逆序数为增加了n-arr[i]-1-arr[i]个逆序数(当然有可能是减小了,视arr[i]的值而定。

2 如何求一个数列的逆序数

可以使用归并排序来求,也可以使用线段树来求。两者都是二分法的思想,故此时间效率是O(nlgn)


使用线段树来求逆序数是有点难度的,参考了神牛的代码,恍然大悟。

虽然说本题线段树应该不如使用归并排序那么好,但是确实灵活运用线段树的极好例子。

这些数据结构就犹如神兵利器,让我们有可能战胜比自己更加强大的敌人。


#pragma once
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
 
class MinimumInversionNumber_2
{
	static const int SIZE = 5001;
	int *segTree;
	inline int lChild(int r) { return r<<1; }
	inline int rChild(int r) { return r<<1|1; }

	void pushUp(int rt)
	{
		segTree[rt] = segTree[lChild(rt)] + segTree[rChild(rt)];
	}

	void build(int l, int r, int rt)
	{
		segTree[rt] = 0;
		if (l == r) return ;

		int m = l + ((r-l)>>1);
		build(l, m, lChild(rt));
		build(m+1, r, rChild(rt));
	}

	void update(int p, int l, int r, int rt)
	{
		if (l == r)
		{
			segTree[rt]++;
			return;
		}
		int m = l + ((r-l)>>1);
		if (p <= m) update(p, l, m, lChild(rt));
		else update(p, m+1, r, rChild(rt));
		pushUp(rt);
	}

	int query(const int L, const int R, int l, int r, int rt)
	{
		if (L <= l && r <= R)
		{
			return segTree[rt];
		}
		int m = l + ((r-l)>>1);
		int res = 0;
		if (L <= m) res += query(L, R, l, m, lChild(rt));
		if (R > m) res += query(L, R, m+1, r, rChild(rt));
		return res;
	}

public:
	MinimumInversionNumber_2() : segTree((int *) malloc(sizeof(int) * (SIZE<<2)))
	{
		int n;
		int arr[SIZE];

		while (~scanf("%d", &n))
		{
			build(0, n-1, 1);
			int sum = 0;
			for (int i = 0; i < n; i++)
			{
				scanf("%d", &arr[i]);
				sum += query(arr[i], n-1, 0, n-1, 1);
				update(arr[i], 0, n-1, 1);
			}

			int ans = sum;
			for (int i = 0; i < n; i++)
			{
				/*计算逆序数的公式, 一个数arr[i]从前面放到后面,必然会有n-arr[i]-1个数比这个大,那么就有n-arr[i]-1个逆序数增加,同时因为前面少了个arr[i]数,那么就必然有arr[i]个(加上零)数比起小的数失去一个逆序数,总共失去arr[i]个逆序数,所以新的逆序数为增加了n-arr[i]-1-arr[i]个逆序数*/
				sum += n - arr[i] - 1 - arr[i];
				ans = min(ans, sum);
			}
			printf("%d\n", ans);
		}
	}

	~MinimumInversionNumber_2()
	{
		free(segTree);
	}
};



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的影城管理系统,源码+数据库+论文答辩+毕业论文+视频演示 随着现在网络的快速发展,网上管理系统也逐渐快速发展起来,网上管理模式很快融入到了许多生活之中,随之就产生了“小徐影城管理系统”,这样就让小徐影城管理系统更加方便简单。 对于本小徐影城管理系统的设计来说,系统开发主要是采用java语言技术,在整个系统的设计中应用MySQL数据库来完成数据存储,具体根据小徐影城管理系统的现状来进行开发的,具体根据现实的需求来实现小徐影城管理系统网络化的管理,各类信息有序地进行存储,进入小徐影城管理系统页面之后,方可开始操作主控界面,主要功能包括管理员:首页、个人中心、用户管理、电影类型管理、放映厅管理、电影信息管理、购票统计管理、系统管理、订单管理,用户前台;首页、电影信息、电影资讯、个人中心、后台管理、在线客服等功能。 本论文主要讲述了小徐影城管理系统开发背景,该系统它主要是对需求分析和功能需求做了介绍,并且对系统做了详细的测试和总结。具体从业务流程、数据库设计和系统结构等多方面的问题。望能利用先进的计算机技术和网络技术来改变目前的小徐影城管理系统状况,提高管理效率。 关键词:小徐影城管理系统;Spring Boot框架,MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值