HRBUST - 2224 逆序对数(树状数组)
2018-03-29 19:15
274 查看
problem
给定 n 个数组成的数组,求其逆序对的总数。逆序对定义为,存在 (i, j) 满足 i < j 且 A[i] > A[j] 的二元组的数目。
Input
第一行包含一个整数,表示数组的项数。接下来的一行,包含 n 个数(2 <= n <= 100000),依次表示 A[i](A[i] <= 10^9)。
Output
输出一行表示对应的答案。。Sample Input
51 3 2 5 4
Sample Output
2思路
对于一个从左往右的序列的,我们可以这样来统计逆序对数考虑与前面已经出现的数可能出现逆序
那第一个数肯定无法构成逆序对
对于第二数 我关注第1个数
对于第三个数 我关注1~2个数
……
那可以对于每个数 先做个a[i]+1 ~n的查询 (维护一个区间和)即这么多数之前有没有出现过(但开一个数组v记录)
然后把v[a[i]]++
但发现到数的范围可能会很大
但是数量是1e5
于是想到离散化
即对于逆序对数 我只关注这些数之间的相对大小关系 辣我排个序搞一下就行
(可以用pair记一下之前的id
也可以只排序再二分定位 )
注意使用long long 逆序对数最大是n2n2左右的
代码示例
//求逆序对数 注意离散化 #include<iostream> #include<algorithm> using namespace std; const int maxn=1e5+10; typedef pair<int,int > pir; typedef long long ll; int node[maxn]; int a[maxn]; pir b[maxn];//辅助数组 int n; inline int lowbit(int x) { return x&(-x); } void add(int a,int b) { for(int i=a;i<=n;i+=lowbit(i)){ node[i]+=b; } } ll sum(int n)//前缀和 { ll res=0; for(int i=n;i;i-=lowbit(i)){ res+=node[i]; } return res; } int main() { //freopen("in.txt","r",stdin); ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;++i){ cin>>b[i].first; b[i].second=i; } sort(b+1,b+n+1); int k=1; a[b[1].second]=k;//离散化后的值 4000 for(int i=2;i<=n;++i){ if(b[i].first!=b[i-1].first) a[b[i].second]=++k; else a[b[i].second]=k; } //for(int i=1;i<=n;++i) cout<<a[i]<<" "; ll ans=0; // for(int i=1;i<=n;++i){ // add(i,a[i]); // } for(int i=1;i<=n;++i){ ans+=sum(n)-sum(a[i]); add(a[i],1); } cout<<ans<<endl; return 0; }
二分离散化
//求逆序对数 注意离散化 #include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; typedef long long ll; int node[maxn]; int a[maxn]; int b[maxn];//辅助数组 int n; inline int lowbit(int x) { return x&(-x); } void add(int a,int b) { for(int i=a;i<=n;i+=lowbit(i)){ node[i]+=b; } } ll sum(int n)//前缀和 { ll res=0; for(int i=n;i;i-=lowbit(i)){ res+=node[i]; } return res; } int main() { //freopen("in.txt","r",stdin); ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;++i){ cin>>a[i]; b[i]=a[i]; } sort(b+1,b+n+1); for(int i=1;i<=n;++i){ a[i]=lower_bound(b+1,b+1+n,a[i])-b; } //for(int i=1;i<=n;++i) cout<<a[i]<<" "; ll ans=0; for(int i=1;i<=n;++i){ ans+=sum(n)-sum(a[i]); //cout<<ans<<endl; add(a[i],1); } cout<<ans<<endl; return 0; }
相关文章推荐
- Hrbust 2224 逆序对问题【归并排序/离散化树状数组】
- poj2299 B - Ultra-QuickSort(线段树与树状数组求逆序对数)
- (POJ 2299)Ultra-QuickSort 树状数组求逆序对数 + 离散化
- poj 2299 树状数组求逆序对数+离散化
- 树状数组求逆序对数
- 树状数组求逆序对数
- 【BestCoder Round 65C】【树状数组 动态查找第k大 O(nlogn)】ZYB's Premutation 告诉你前i个数中的逆序对数让你还原全排列
- 用树状数组求逆序对数(poj2299)
- SGU 180-Inversions(树状数组离散化求逆序对数)
- 蓝桥杯 历届试题 小朋友排队(归并,树状数组求逆序对数)
- 树状数组与逆序对数
- 2789: [Poi2012]Letters (树状数组求逆序对数)
- 树状数组求逆序对数板子
- POJ 2299 利用树状数组求逆序对数
- poj2299 Ultra-QuickSort&&NYOJ117 求逆序数 (树状数组求逆序对数+离散化)+(归并排序)
- 离散化+树状数组 求逆序对数
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- HDU 4911 Inversion(树状数组求逆序对数 + 数据离散化)
- Ultra-QuickSort(树状数组求逆序对数)
- POJ-2299 Ultra-QuickSort (树状数组 离散 求逆序对数)