【线段树】HDU1394 - Minimum Inversion Number
【题目大意】
给出0..n-1组成的一段数,可以移动前几个数到结尾。求出最小的逆序对个数。
【思路】
先用线段树求出逆序对,方法和树状数组是一样的。然后对于当前第一个数num[0],在它之后比它小的数有num[0],则它移动到末位之后减小的逆序对是num[0],增加的是n-1-num[0]。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define lson l,m,root<<1 8 #define rson m+1,r,root<<1|1 9 const int MAXN=5000+50; 10 int n,num[MAXN]; 11 int sum[MAXN*4]; 12 int inver[MAXN]; 13 14 void pushUP(int root) 15 { 16 sum[root]=sum[root<<1]+sum[root<<1|1]; 17 } 18 19 void build(int l,int r,int root) 20 { 21 if (l==r) 22 { 23 sum[root]=0; 24 return; 25 } 26 int m=(l+r)>>1; 27 build(lson); 28 build(rson); 29 pushUP(root); 30 } 31 32 void update(int p,int delta,int l,int r,int root) 33 { 34 if (l==r) 35 { 36 sum[root]+=delta; 37 return; 38 } 39 int m=(l+r)>>1; 40 if (p<=m) update(p,delta,lson); 41 if (p>m) update(p,delta,rson); 42 pushUP(root); 43 } 44 45 int query(int L,int R,int l,int r,int root) 46 { 47 if (L<=l && r<=R) 48 { 49 return sum[root]; 50 } 51 int m=(l+r)>>1,res=0; 52 if (L<=m) res+=query(L,R,lson); 53 if (R>m) res+=query(L,R,rson); 54 return res; 55 56 } 57 58 int main() 59 { 60 while (scanf("%d",&n)!=EOF) 61 { 62 build(0,n-1,1); 63 for (int i=0;i<n;i++) 64 { 65 scanf("%d",&num[i]); 66 inver[i]=query(num[i]+2,n,1,n,1); 67 update(num[i]+1,1,1,n,1); 68 } 69 int tempsum=0; 70 for (int i=0;i<n;i++) tempsum+=inver[i]; 71 int ans=tempsum; 72 for (int i=0;i<n;i++) 73 { 74 tempsum-=num[i]; 75 tempsum+=n-1-num[i]; 76 ans=min(ans,tempsum); 77 } 78 cout<<ans<<endl; 79 } 80 return 0; 81 }