逆序对——树状数组
逆序对
题目描述
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中
输入格式
第一行,一个数
第二行
输出格式
输出序列中逆序对的数目。
样例 #1
样例输入 #1
6
5 4 2 6 3 1
样例输出 #1
11
提示
对于
对于
对于所有数据,
思路:
问题解答
Q1: 如何统计第 个数会与第 ~ 个数构成多少个逆序对呢?
Ans1: 可以通过建立一个树状数组来解决这个问题。初始时,树状数组的所有元素都为
Q2: 根据 来建树状数组空间不够啊?
Ans2: 确实,直接根据
Q3: 相等的元素是否会导致求解错误?每一个数(不管是否相等)对应的新数都不同诶?
Ans3: 如果不处理相等的元素,确实会导致错误。问题的关键在于是否有与
总结
通过建立树状数组并结合离散化处理,可以高效地统计序列中每个元素与其之前的元素构成的逆序对数量。离散化确保了空间复杂度在可接受范围内,而排序时考虑元素出现顺序则避免了相等元素导致的错误。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+100,mod=998244353;
typedef long long ll;
typedef pair<int,int> PII;
int T;
int n,m;
struct node
{
int id;
int s;
}a[N],b[N];
bool cmp(node a,node b)
{
if(a.s!=b.s) return a.s<b.s;
else return a.id<b.id;
}
int c[N];
int ranks[N];
int lowbit(int x)
{
return x&(-x);
}
int query(int x)
{
int s=0;
for(;x>0;x-=lowbit(x))
{
s+=c[x];
}
return s;
}
void modify(int id,int x)
{
for(;id<=n;id+=lowbit(id))
{
c[id]+=x;
}
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].s,a[i].id=i;
sort(a+1,a+1+n,cmp);
int ans=0;
for(int i=1;i<=n;i++) ranks[a[i].id]=i;
for(int i=n;i>=1;i--)
{
int idx=ranks[i];
ans+=query(idx-1);
modify(idx,1);
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
T=1;
//cin>>T;
while(T--)
{
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异