POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树
题目链接:http://poj.org/problem?id=2299
求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法。
归并排序:
#include<cstdio> #include<iostream> using namespace std; #define max 500002 int arr[max],b[max];//b[]为临时序列,arr[]为待排序数列,结果在arr[]中 int tp[max]; long long cnt=0;//总逆序数 void Merge(int a[],int start,int mid,int end){ int i =start,j=mid+1,k=start; while(i<=mid&&j<=end){ if(a[i]<=a[j]){ cnt+=j-mid-1; b[k++]=a[i++]; }else{ cnt+=j-k; b[k++]=a[j++]; } } while(i<=mid){ cnt+=end-mid; b[k++]=a[i++]; } while(j<=end){ b[k++]=a[j++]; } for(int i=start;i<=end;i++){ a[i]=b[i]; } } void MergeSort(int a[], int start,int end){ if(start<end){ int mid=(start+end)/2; MergeSort(a,start,mid); MergeSort(a,mid+1,end); Merge(a,start,mid,end); } } int main(){ int n; while(~scanf("%d",&n)&&n){ for(int i=0;i<n;i++){ scanf("%d",&arr[i]); } cnt=0; MergeSort(arr,0,n-1); printf("%I64d\n",cnt/2); } return 0; }
树状数组:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define lowbit(x) (x&(-x)) using namespace std; const int MAX = 500005; struct data{ int id,val; }num[MAX]; int n, C[MAX]; bool cmp(data a, data b){ return a.val>b.val; } void add(int i){ while(i<=n){ C[i]+=1; i+=lowbit(i); } } long long sum(int i){ long long ans = 0; while(i>0){ ans+=C[i]; i-=lowbit(i); } return ans; } int main(){ while(scanf("%d",&n)&&n){ memset(C,0,sizeof(C)); for(int i=0;i<n;i++){ num[i].id=i+1; scanf("%d",&num[i].val); } sort(num,num+n,cmp);//离散化,将数组按降序排序,再求下标的逆序数,下标的逆序数与值逆序数相等 long long ans = 0; for(int i=0;i<n;i++){ ans+=sum(num[i].id-1);//求在i前面比第i个数大的数的个数 add(num[i].id); } printf("%I64d\n", ans); } return 0; }
线段树( 以HDU1394 Minimum Inversion Number为例):
#include<iostream> #include<cstdio> #include<cstdlib>#include<algorithm> const int INF = 0x3F3F3F3F; using namespace std; #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define N 5008 int sum[N<<2], a[N]; inline void pushUp(int rt){ sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } int query(int a, int b, int l, int r, int rt){ if(a <= l && b >= r){ return sum[rt]; } int m=(l + r) >> 1; int ret=0; if(a <= m){ ret += query(a, b, lson); } if(b > m){ ret += query(a, b, rson); } return ret; } void update(int x, int val, int l, int r, int rt){ if(l == r){ sum[rt] = val; }else{ int m = (l + r)/2; if(x <= m){ update(x, val, lson); }else{ update(x, val, rson); } pushUp(rt); } } int main(){ int n; while(~scanf("%d", &n)){ memset(sum, 0, sizeof(sum)); int ans = 0; for(int i = 0 ; i < n; i++){ scanf("%d", &a[i]); a[i]++; ans += query(a[i] + 1, n, 1, n , 1); update(a[i], 1, 1, n, 1); } int tp = ans; for(int i = 0 ; i < n - 1; i++){ tp += n - 2 * a[i] + 1; ans = min(ans , tp); } printf("%d\n",ans); } }