luogu里也有我的这篇题解(asd_a)
大佬应该都用的是树状数组和归并,我就讲一讲线段树的方法吧!
逆序对就是求每一个数前面有多少个比它大,
则考虑权值线段树。
什么是权值线段树? 就是以数的大小作区间的线段树。
权值线段树可干啥?整体第k大……(其实就是在区间比大小)
我们就只用查询线段树中有多少个比他大,然后再加入线段树
答案之和就是逆序对个数(是不是很神奇啊)
然而,此题数据范围太大,所以需要一个小小的预处理操作:
例:2 8 0 3 2,
我们可以排个序(要保留原版):0 2 2 3 8
去重:0 2 3 8,
编号为:1,2,3,4。再对应回去:2 4 1 3 2
(要开个结构体,记录原位置)
一系列骚操作得: 1<=AiA_iAi<=n
好了,现在可以构造了。(开始值都为0)
coding:
(代码有点丑,望大佬谅解 orz)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
inline int rd()
{
int x=0,flag=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
inline LL rdl()
{
LL x=0,flag=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}//读入优化
const int N=5e5+50;
const int TR=N<<2;
struct tree{
int l,r,k;
}t[TR];
inline int ls(int x)//左儿子
{
return x<<1;
}
inline int rs(int x)//右儿子
{
return x<<1|1;
}
struct no{
int x,i;
}cop[N];
bool comp(no x,no y)
{
return x.x<y.x;
}
inline void build(int now,int l,int r)//建树
{
t[now].l=l;
t[now].r=r;
t[now].k=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(ls(now),l,mid);
build(rs(now),mid+1,r);
return ;
}
inline void up(int now)//回溯
{
t[now].k=t[rs(now)].k+t[ls(now)].k;
}
inline LL src(int now,int x)//搜索
{
int l=t[now].l,r=t[now].r;
LL sum=0;
int mid=(l+r)>>1;
if(l==r)
return (LL)t[now].k;
if(x<=mid) sum+=(LL)t[rs(now)].k+src(ls(now),x);//若在左儿子中,右儿子一定比它大
else sum+=src(rs(now),x);//搜索右儿子
return sum;
}
inline void upate(int now,int x)//加入
{
int l=t[now].l,r=t[now].r;
int mid=(l+r)>>1;
if(l==r)
{
t[now].k++;//统计个数
return ;
}
if(x<=mid) upate(ls(now),x);
else upate(rs(now),x);
up(now);
}
int n;
LL a[N],k[N],tot=0,ans=0;//开long long防爆
int main()
{
n=rd();
for(int i=1;i<=n;i++) a[i]=rdl(),cop[i].x=a[i],cop[i].i=i;
sort(cop+1,cop+n+1,comp);
for(int i=1;i<=n;i++)
{
if(cop[i].x!=cop[i-1].x || i==1)
k[++tot]=cop[i].x;
a[cop[i].i]=tot;
}//预处理
build(1,1,n);
for(int i=1;i<=n;i++)
{
ans+=src(1,a[i]+1);//大于a的个数=大于等于a+1的个数
upate(1,a[i]);//更新
}
cout<<ans<<endl;
return 0;
}