51Nod-1019 逆序數【逆序偶+歸併排序】
阿新 • • 發佈:2018-12-19
1019 逆序數
在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序數是4。給出一個整數序列,求該序列的逆序數。
Input
第1行:N,N為序列的長度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9) Output
輸出逆序數 Input示例
4 2 4 3 1 Output示例
4
問題連結:51Nod-1019 逆序數
程式碼1(線段樹):
#include<cstdio> #include<cstring> #include<cstdlib> #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int maxn=5e4+100; #define ll long long int a[maxn]; int x[maxn]; struct Tree { int left,right; int val; }tree[maxn<<2]; void build(int l,int r,int root) { tree[root].left=l; tree[root].right=r; tree[root].val=0; if(l==r) return ; int mid=l+r>>1; build(l,mid,root<<1); build(mid+1,r,root<<1|1); } int query(int l,int r,int root) { if(l==tree[root].left&&tree[root].right==r) { return tree[root].val; } int mid=tree[root].left+tree[root].right>>1; if(l>mid) return query(l,r,root<<1|1); else if(r<=mid) return query(l,r,root<<1); else return query(l,mid,root<<1)+query(mid+1,r,root<<1|1); } //包含id的區間都加1 void update(int id,int root) { tree[root].val++; if(tree[root].left==tree[root].right) { return ; } int mid=tree[root].left+tree[root].right>>1; if(mid>=id) update(id,root<<1); else update(id,root<<1|1); } int Bin(int key,int n) { int l=0; int r=n-1; while(l<=r) { int mid=l+r>>1; if(x[mid]>key) r=mid-1; else if(x[mid]==key) return mid; else l=mid+1; } return 1; } int main() { int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); x[i]=a[i]; } sort(x,x+n); int m=1; for(int i=1;i<n;i++) { if(x[i]>x[m-1]) x[m++]=x[i]; } build(1,50005,1); int sum=0; for(int i=0;i<n;i++) { int id=Bin(a[i],m)+1; sum+=query(id+1,50005,1); update(id,1); } printf("%d\n",sum); return 0; }
解法2(歸併演算法):(拷了海島的程式碼)
/* 51Nod-1019 逆序數 */ #include <bits/stdc++.h> using namespace std; const int N = 50000; int a[N], temp[N], cnt; void merge(int low, int middle, int high) { int i = low, j=middle+1, k = low; while(i <= middle && j <= high) { if(a[i] < a[j]) temp[k++] = a[i++]; else { cnt += j - k; temp[k++] = a[j++]; } } while(i <= middle) temp[k++] = a[i++]; while(j <= high) temp[k++] = a[j++]; for(i=low; i<=high; i++) a[i] = temp[i]; } void mergesort(int low, int high) { if(low < high) { int middle = (low + high) / 2; mergesort(low, middle); mergesort(middle+1, high); merge(low, middle, high); } } int main() { int n; while(~scanf("%d", &n)) { for(int i = 0; i < n; i++) scanf("%d", &a[i]); cnt = 0; mergesort(0, n - 1); printf("%d\n", cnt); } return 0; }