求逆序对(线段树版)

本文介绍了一种利用线段树优化的方法来解决逆序对问题。传统方法通过枚举所有元素对,复杂度为O(n^2),而通过建立一个数组并维护每个数出现的次数,再配合线段树进行查找和增加操作,可以将复杂度降低到O(nlogn)。当数值范围过大时,采用离散化技术将数值映射到1~n,进一步优化解决方案。以POJ2299题目为例,详细阐述了这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个序列a1,a2,a3...aN,求出满足:ai > aj 且 i < j 的个数。

一个最容易想到的方法就是枚举所有的i,j看看是否满足,显然是O(n^2)的复杂度。不够好。

可以这样考虑,开一个数组保存这n个数出现的位置和对应的次数,这个数组要开到a数组里最大的那个数MAX,也就是hash,初始状态数组里没有元素,每个数对应的个数都是0.

如果考虑第i个数,找到比它大的所有的数 的个数,查找的范围即 ai+1~MAX,这就是到i这个位置的逆序对的总和,接着把a[i]这个数添加到数组里,也就是a[i]这个位置的数量加1。一直进行到n结束,逆序对就求了出来。

这样做得复杂度依然是O(n^2),但查找和增加的操作可用线段树解决,这样复杂度就降到了O(nlogn)。

还有一个问题,如果a[i]可以达到10^9甚至更大,数组都开不下,即便开的下,时间上也不能承受,这样就要用到离散化,将n个数映射到1~n的范围内,这个操作排序加二分可轻松解决。所有数控制在n 的范围内,线段树解决是非常理想的。


以POJ2299为例 : 题目就是要求逆序对。详见代码:


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <stack>
#include <cctype>
#include <algorithm>
#define lson o<<1, l, m
#define rson o<<1|1, m+1, r
using namespace std;
typedef long long LL;
const int maxn = 500500;
const int MAX = 0x3f3f3f3f;
int n, a, b,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值