POJ[2299]Ultra-QuickSort 逆序对:线段树||树状数组||分治
2017-09-06 22:02
615 查看
题目链接:http://poj.org/problem?id=2299
题目大意:给n个数(n≤50000),求逆序对数
求逆序对是一种经典题型,今天整理一下(闲的蛋疼)各种写法的逆序对…
复杂度都是O(nlogn)
![](http://img.blog.csdn.net/20170906215007204?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvV0FEdWFuMg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
线段树代码:
树状数组代码:
归并排序算法:
题目大意:给n个数(n≤50000),求逆序对数
求逆序对是一种经典题型,今天整理一下(闲的蛋疼)各种写法的逆序对…
复杂度都是O(nlogn)
树状数组的思想就是对于每个数找出之前有k个数比他大,这个k就是对答案的贡献
可以用开个树状数组a[i]表示1~i有多少个数,则比i大的数一共有i-Sum(i)+1(后插入i)个数(也可以倒着开…)
优点:思维复杂度低 缺点:代码比较长,数据过大时要离散化,常数比分治(归并排序)略大
线段树的思想和树状数组差不多
记录答案只需要查询Sum(i+1,MAXN)即可…
优点:更好消磨时间 缺点:代码长,常数大,容易MLE,也要离散化
分治(归并排序)可能是最优的写法了吧…
和正常分治的思路一样,先处理左右区间(对他们从小到大排序)然后找出某时a[i]>a[j],则i的贡献就是mid-i+1
优点:代码短 常数小 缺点:递归层数深时容易崩溃..
不同算法的效率比较(从上至下依次为 线段树 树状数组 分治):线段树代码:
#include<algorithm> #include<cstring> #include<ctype.h> #include<cstdio> using namespace std; int n,x,tmp,maxn,cnt,top=1; long long ans; inline int max(int a,int b) {return a>b?a:b;} int a[500020],b[500020]; struct Seg{ int sum,l,r; Seg *ls,*rs; }q[2000020]; inline int read(){ char c=getchar(); int x=0,f=1; while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();} return x*f; } bool cmp(int a,int b){return a<b;} void maketree(int l,int r,Seg *k){ k->l=l;k->r=r; if(l==r){ k->sum=0; return; } k->ls=&q[++top];k->rs=&q[++top]; int mid=(l+r)>>1; maketree(l,mid,k->ls);maketree(mid+1,r,k->rs); k->sum=k->ls->sum+k->rs->sum; } int Query_sum(int x,int y,Seg *k){ if(k->l>=x && k->r<=y) return k->sum; int mid=(k->l+k->r)>>1; if(mid>=y) return Query_sum(x,y,k->ls); if(mid<x) return Query_sum(x,y,k->rs); return Query_sum(x,y,k->ls)+Query_sum(x,y,k->rs); } void add(int x,int v,Seg *k){ if(k->l==k->r){ k->sum=v; return; } int mid=(k->l+k->r)>>1; if(x<=mid) add(x,v,k->ls); else add(x,v,k->rs); k->sum=k->ls->sum+k->rs->sum; } main(){ maketree(1,500020,&q[1]); while(""){ for(int i=1;i<=2000000;i++) q[i].sum=0; ans=0; n=read(); if(!n) break; for(int i=1;i<=n;i++) b[i]=a[i]=read(); sort(b+1,b+n+1,cmp); cnt=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++){ x=lower_bound(b+1,b+cnt+1,a[i])-b; ans=ans+Query_sum(x+1,500000,&q[1]); add(x,1,&q[1]); } printf("%lld\n",ans); } return 0; }
树状数组代码:
#include<algorithm> #include<cstring> #include<ctype.h> #include<cstdio> #define int long long using namespace std; int n,x,tmp,maxn,cnt; long long ans; inline int max(int a,int b) {return a>b?a:b;} int s[500020],a[500020],b[500020]; inline int read(){ char c=getchar(); int x=0,f=1; while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();} return x*f; } inline int lowbit(int x){return x&-x;} inline int sum(int x){ for(tmp=0;x;x=x-(x&-x)) tmp=tmp+s[x]; return tmp; } inline int add(int x,int v){ for(;x<=500000;x=x+(x&-x)) s[x]=s[x]+v; } bool cmp(int a,int b){return a<b;} main(){ while(""){ ans=0; n=read(); if(!n) break; memset(s,0,sizeof s); for(int i=1;i<=n;i++) b[i]=a[i]=read(); sort(b+1,b+n+1,cmp); cnt=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++){ x=lower_bound(b+1,b+cnt+1,a[i])-b; ans=ans+i-sum(x)-1; add(x,1); } printf("%lld\n",ans); } return 0; }
归并排序算法:
#include<algorithm> #include<cstdio> #define int long long using namespace std; int n,ans; int a[500020],s[500020]; void calc(int l,int r){ if(l==r) return; int mid=(l+r)>>1,p=l,q=mid+1,top=l; calc(l,mid);calc(mid+1,r); while(p<=mid||q<=r){ if(q>r||(p<=mid&&a[p]<=a[q]))s[top++]=a[p++]; else {s[top++]=a[q++];ans=ans+mid+1-p;} } for(int i=l;i<=r;i++) a[i]=s[i]; } main(){ while(""){ ans=0; scanf("%lld",&n); if(!n) break; for(int i=1;i<=n;i++) scanf("%lld",a+i); calc(1,n); printf("%lld\n",ans); } return 0; }
相关文章推荐
- poj2299 B - Ultra-QuickSort(线段树与树状数组求逆序对数)
- POJ 2299 Ultra-QuickSort (树状数组求逆序数 || 线段树 +离散化)
- POJ 2299 Ultra-QuickSort 求逆序数 线段树或树状数组 离散化
- poj 2299 Ultra-QuickSort 【线段树 or 线段树+lazy or 树状数组 or 归并排序】 求逆序对
- POJ 2299 Ultra-QuickSort【树状数组 ,逆序数】
- POJ 2299 Ultra-QuickSort(归并排序 || 树状数组 || 线段树)
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- poj 2299 Ultra-QuickSort 树状数组求逆序数 离散化
- POJ 题目2299 Ultra-QuickSort(树状数组求逆序对)
- poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)
- [树状数组 逆序对] poj 2299 Ultra-QuickSort
- POJ 2299 Ultra-QuickSort (树状数组求逆序数+离散化)
- POJ 2299 Ultra-QuickSort 【归并排序求逆序数 OR 树状数组求逆序数】
- POJ 2299 Ultra-QuickSort(离散化+树状数组求逆序对)
- POJ-2299 Ultra-QuickSort (树状数组 离散 求逆序对数)
- poj 2299 Ultra-QuickSort(数学:求逆序数||数据结构:树状数组)
- Poj 2299 - Ultra-QuickSort 离散化,树状数组,逆序对
- Ultra-QuickSort (poj 2299 归并排序 || 树状数组 求逆序对)
- poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)
- POJ 2299 Ultra-QuickSort(树状数组+离散化 或 归并排序求逆序)