这几天考试考得心里颇不宁静,来水篇博客散散心。
好滴,接下来,我们进入正题--
相信许多人都知道逆序对吧,传说中归并排序的方法在这先不讲,我们来了解一下用权值线段树如何解决这个问题:
首先,我们需预处理,得到每个值在权值线段树中的位置;
然后,按顺序将数字(a[i])插入到树中相应的位置(id[a[i]]),接着询问树中比它大的元素个数(id[a[i]]+1~n),容易知道这些数都与当前的数(a[i])形成逆序对,将它累加到答案(ans)里就行啦,很简单吧!
代码如下:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define maxn 50001
#define ls node<<1
#define rs node<<1|1
using namespace std;
int n,a[maxn];
struct node{
int w,id;
}now[maxn];
int e,id[maxn],tree[maxn<<2];
inline bool cmp(node a,node b){ return a.w<b.w; }
inline void Y(){
sort(now+1,now+n+1,cmp);
For(i,1,n){
id[now[i].id]=++e;
while(now[i+1].w==now[i].w) id[now[++i].id]=e;
}
}
inline void insert(int node,int x,int l=1,int r=e){
++tree[node];
if(l==r) return ;
int mid=(l+r)>>1;
if(x>mid) insert(rs,x,mid+1,r);
else insert(ls,x,l,mid);
}
inline int query(int node,int z,int y,int l=1,int r=e){
if(l==z && r==y) return tree[node];
int mid=(l+r)>>1;
if(y<=mid) return query(ls,z,y,l,mid);
else if(z>mid) return query(rs,z,y,mid+1,r);
else return query(ls,z,mid,l,mid)+query(rs,mid+1,y,mid+1,r);
}
inline void solve(){
scanf("%d",&n);
For(i,1,n) scanf("%d",&a[i]),now[i].w=a[i],now[i].id=i;
Y();
int ans=0;
For(i,1,n){
insert(1,id[i]);
if(id[i]==n) continue;
ans+=query(1,id[i]+1,e);
}
printf("%d",ans);
}
int main(){
solve();
return 0;
}
大家若想更深了解权值线段树,就看看这篇吧(KPI的权值线段树解法)
http://blog.csdn.net/Monkey_king2017cn/article/details/55805485