P1908 逆序对

· · 个人记录

原题目

选择算法

可以选择归并排序,但是这里用树状数组。 ## 具体分析 逆序对,简单来说就是两个数中较大的数放在较小的数的前面。 而线段树经常用来求带修改元素的部分和。 有没有一种可能,记下序列中每个数排第几,然后将序列进行从大到小排序。接着按照排序后的顺序,把树状数组arr的ord(每个数的输入时的序号)元素增加1,ans累加arr的元素1..ord-1;表示把排在当前元素前面,而又比当前元素大(由于已经按元素的从大到小的顺序插入)的元素个数累加起来。 注意:记得用稳定排序,对比的两个元素的值相同时还是按照原来的顺序。 ## Source Code ```cpp #include<bits/stdc++.h> using namespace std; const int N=5e5+1; #define int long long struct ele { int val,ord; }a[N]; int n,tr[N],ans; int lowbit(int a) { return a&(-a); } void add(int x,int k) { for(;x<=n;x+=lowbit(x)) tr[x]+=k; } int query(int x) { int sum=0; for(;x>0;x-=lowbit(x)) sum+=tr[x]; return sum; } signed main() { scanf("%lld",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i].val); a[i].ord=i; } stable_sort(a+1,a+1+n,*[](ele a,ele b){ if(a.val==b.val) return a.ord>b.ord; return a.val>b.val; }); for(int i=1;i<=n;i++) { add(a[i].ord,1); ans+=query(a[i].ord-1); } printf("%lld",ans); } ```