逆序对—权值线段树

   这几天考试考得心里颇不宁静,来水篇博客散散心。
   好滴,接下来,我们进入正题--

相信许多人都知道逆序对吧,传说中归并排序的方法在这先不讲,我们来了解一下用权值线段树如何解决这个问题:
首先,我们需预处理,得到每个值在权值线段树中的位置;
然后,按顺序将数字(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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值