我们都知道,求逆序对数量可以用归并排序解决。但是用归并排序只能解决静态的序列问题,没有扩展的区间。因此就有了用权值线段树求逆序对的方法。
1 #include<iostream> 2 #include<iomanip> 3 #include<ctime> 4 #include<climits> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #include<cstring> 9 #include<cstdio> 10 #include<cstdlib> 11 using namespace std; 12 typedef unsigned long long LL; 13 #define rep(i,a,b) for(int i=a;i<=b;i++) 14 #define dep(i,a,b) for(int i=a;i>=b;i--) 15 inline int read(){ 16 int x=0;char ch=getchar(); 17 while(ch<'0'||ch>'9'){ 18 ch=getchar(); 19 } 20 while(ch>='0'&&ch<='9'){ 21 x=x*10+ch-'0'; 22 ch=getchar(); 23 } 24 return x; 25 } 26 const int M=100001; 27 int sum[M<<2]={0};//建立一棵空线段树 28 int a[M];//如果a[i]数据范围较大,则需要离散化 29 #define lson l,m,rt<<1 30 #define rson m+1,r,rt<<1|1 31 void update(int rt){ 32 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 33 } 34 void modify(int l,int r,int rt,int p){ 35 if(l==r){ 36 sum[rt]++;//权值p累和 37 return; 38 } 39 int m=(l+r)>>1; 40 if(p<=m)modify(lson,p); 41 else modify(rson,p); 42 update(rt); 43 } 44 int query(int l,int r,int rt,int nowl,int nowr){ 45 if(nowl<=l&&r<=nowr)return sum[rt]; 46 int ans=0; 47 int m=(l+r)>>1; 48 if(nowl<=m)ans+=query(lson,nowl,nowr); 49 if(m<nowr)ans+=query(rson,nowl,nowr); 50 return ans; 51 } 52 int main(){ 53 int n=read(); 54 rep(i,1,n)a[i]=read(); 55 LL ans=0; 56 rep(i,1,n){ 57 ans+=query(1,n,1,a[i]+1,M);//求以a[i]为末项的逆序对数时,转化为求a[1..(i-1)]中权值大于a[i]的数的个数 58 modify(1,n,1,a[i]);//权值a[i]累积入权值线段树 59 } 60 cout<<ans<<endl; 61 return 0; 62 }
附上百度的离散化定义:
把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:
原数据:1,999,100000,15;处理后:1,3,4,2;
原数据:{100,200},{20,50000},{1,400};
处理后:{3,4},{2,6},{1,5};