逆序对
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
输入输出格式
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
输出格式:
给定序列中逆序对的数目。
输入输出样例
说明
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
分析:
用归并或者树状数组都可以轻易A掉,但是这里用权值线段树。可以算是一道权值线段树的模板题。用于理解权值线段树。
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+7; 5 int n,p[maxn];ll ans; 6 struct Num{ 7 int id,val; 8 }a[maxn]; 9 struct Seg{ 10 int l,r;ll val; 11 }seg[maxn<<2]; 12 inline void pushup(int rt) 13 { 14 seg[rt].val=seg[rt<<1].val+seg[rt<<1|1].val; 15 } 16 inline void build(int l,int r,int rt) 17 { 18 seg[rt].l=l,seg[rt].r=r; 19 if(l==r){seg[rt].val=0;return;} 20 int mid=(l+r)>>1; 21 build(l,mid,rt<<1); 22 build(mid+1,r,rt<<1|1); 23 } 24 inline void update(int rt,int x) 25 { 26 if(seg[rt].l==seg[rt].r&&seg[rt].l==x){ 27 seg[rt].val++;return;} 28 int mid=(seg[rt].l+seg[rt].r)>>1; 29 if(x<=mid)update(rt<<1,x); 30 if(x>mid)update(rt<<1|1,x); 31 pushup(rt); 32 } 33 inline ll quary(int rt,int l,int r) 34 { 35 if(seg[rt].l>r||seg[rt].r<l)return 0; 36 if(l<=seg[rt].l&&seg[rt].r<=r) 37 return seg[rt].val; 38 int mid=(seg[rt].l+seg[rt].r)>>1;int ret=0; 39 if(l<=mid)ret+=quary(rt<<1,l,r); 40 if(r>mid)ret+=quary(rt<<1|1,l,r); 41 return ret; 42 } 43 bool cmp(Num x,Num y) 44 {return x.val<y.val;} 45 int main() 46 { 47 ios::sync_with_stdio(false); 48 cin>>n; 49 build(1,maxn,1); 50 for(int i=1;i<=n;i++) 51 cin>>a[i].val,a[i].id=i; 52 sort(a+1,a+n+1,cmp); 53 for(int i=1;i<=n;i++) 54 p[a[i].id]=i; 55 for(int i=1;i<=n;i++){ 56 ans+=quary(1,p[i]+1,maxn); 57 update(1,p[i]);} 58 cout<<ans<<"\n"; 59 return 0; 60 }