题意:主要是利用线段树求逆序树,建的是一棵空树,然后每插入一个点之前,统计大于这个数的有多少个,直到所有的数都插入完成,就结果了逆序树的统计。
要得出答案主要是利用了一个结论,如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少y[i],而增加n-1-y[i]的。(可以这样想,因为是第一个数,所有的数都在它后面,那么在当前位置pos比它大的数也在它后面,那么第一个数调到后面之后,在pos不成立的逆序数就成立了,所以多了n-y[i]-1,但是也少了在pos成立的逆序数,即y[i]个)
/*代码风格更新后*/ #include <iostream> #include <cstdio> #include <cstring> using namespace std; #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define MID(a,b) (a+((b-a)>>1)) const int N=5005; struct node { int lft,rht,valu; int mid(){return MID(lft,rht);} }; int y[N],n; struct Segtree { node tree[N*4]; void build(int lft,int rht,int ind) { tree[ind].lft=lft; tree[ind].rht=rht; tree[ind].valu=0; if(lft!=rht) { int mid=tree[ind].mid(); build(lft,mid,LL(ind)); build(mid+1,rht,RR(ind)); } } void updata(int pos,int ind) { int lft=tree[ind].lft,rht=tree[ind].rht; if(lft==rht) tree[ind].valu++; else { int mid=tree[ind].mid(); if(pos<=mid) updata(pos,LL(ind)); else updata(pos,RR(ind)); tree[ind].valu=tree[LL(ind)].valu+tree[RR(ind)].valu; } } int query(int st,int ed,int ind) { int lft=tree[ind].lft,rht=tree[ind].rht; if(st<=lft&&rht<=ed) return tree[ind].valu; else { int mid=tree[ind].mid(); int sum1=0,sum2=0; if(st<=mid) sum1=query(st,ed,LL(ind)); if(ed>mid) sum2=query(st,ed,RR(ind)); return sum1+sum2; } } }seg; int main() { while(scanf("%d",&n)!=EOF) { int sum=0; seg.build(0,n-1,1); for(int i=1;i<=n;i++) { scanf("%d",&y[i]); seg.updata(y[i],1); if(y[i]!=n-1) sum+=seg.query(y[i]+1,n-1,1); } int mi=sum; for(int i=1;i<=n;i++) { sum-=y[i]; sum+=n-y[i]-1; mi=min(mi,sum); } printf("%d\n",mi); } return 0; }
/代码风格更新前*/ #include <iostream> #include <cstdio> using namespace std; const int N=500005; int y[N]; struct node { int left,right,cnt; int mid(){return left+(right-left)/2;} }; struct Segtree { node tree[N*4]; void build(int left,int right,int r) { tree[r].left=left; tree[r].right=right; tree[r].cnt=0; if(left<right) { int mid=tree[r].mid(); build(left,mid,r*2); build(mid+1,right,r*2+1); } } void updata(int pos,int r) { if(tree[r].left==tree[r].right) { tree[r].cnt=1; } else { int mid=tree[r].mid(); if(pos<=mid) updata(pos,r*2); else if(pos>mid) updata(pos,r*2+1); tree[r].cnt=tree[r*2].cnt+tree[r*2+1].cnt; } } int query(int be,int end,int r) { if(be<=tree[r].left&&tree[r].right<=end) { return tree[r].cnt; } else { int mid=tree[r].mid(),sum1=0,sum2=0; if(be<=mid) sum1=query(be,end,r*2); if(end>mid) sum2=query(be,end,r*2+1); return sum1+sum2; } } }seg; int main() { int n; while(scanf("%d",&n)!=EOF) { int ans=0; seg.build(0,n-1,1); for(int i=0;i<n;i++) { scanf("%d",&y[i]); ans+=seg.query(y[i]+1,n-1,1); seg.updata(y[i],1); } int imin=ans; for(int i=0;i<n;i++) { ans=ans+n-2*y[i]-1; //printf("ans=%d\n",ans); imin=min(ans,imin); } printf("%d\n",imin); } return 0; }