洛谷p1908逆序对

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 a_i>a_j 且 i<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。

Update:数据已加强。

输入格式

第一行,一个数 n,表示序列中有 n个数。

第二行 n 个数,表示给定的序列。序列中每个数字不超过 10^9。

输出格式

输出序列中逆序对的数目。

n<=5e5

线段树或者树状数组都可以,离散化的时候可以先排序然后用lower_bound找

#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=5e5;
int value[maxn+100];
struct SegTreeNode
{
    int val;
};
SegTreeNode tree[maxn*4+100];
int a[maxn+100];
void updateOne(int root,int nstart,int nend,int index,int addVal);
int query(int root,int nstart,int nend,int qstart,int qend);
int main()
{
    int n,cnt;
    ll ans;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=4*n;i++) tree[i].val=0;
        cnt=0;
        ans=0;
        for(int i=1;i<=n;i++)
            {
                scanf("%d",&value[i]);
                a[i]=value[i];
            }
        sort(value+1,value+1+n);
        cnt=unique(value+1,value+1+n)-value-1;
        for(int i=1;i<=n;i++)
            {
                int temp=lower_bound(value+1,value+1+cnt,a[i])-value;
                updateOne(1,1,cnt,temp,1);
                ans+=query(1,1,cnt,temp+1,cnt);
            }
        cout<<ans<<endl;
    }
    return 0;
}
void updateOne(int root,int nstart,int nend,int index,int addVal)
{
    if(nstart==nend)
    {
        tree[root].val+=1;
        return;
    }
    int mid=(nstart+nend)/2;
    if(index<=mid)
        updateOne(root*2,nstart,mid,index,addVal);
    else updateOne(root*2+1,mid+1,nend,index,addVal);
    tree[root].val=tree[root*2].val+tree[root*2+1].val;
}
int query(int root,int nstart,int nend,int qstart,int qend)
{
    if(qstart>nend||qend<nstart) return 0;
    if(qstart<=nstart&&qend>=nend)
        return tree[root].val;
    int mid=(nstart+nend)/2;
    return query(root*2,nstart,mid,qstart,qend)+query(root*2+1,mid+1,nend,qstart,qend);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值