标签:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define N 5005 6 #define lson rt<<1,l,m 7 #define rson rt<<1|1,m+1,r 8 struct node 9 { 10 int l,r,value; 11 }tree[N<<2]; 12 int a[N]; 13 /* 14 求移位后的最小逆序数 15 Update单点增减 16 Query区间求和 17 */ 18 void Build(int rt,int l,int r) 19 { 20 tree[rt].l=l; 21 tree[rt].r=r; 22 tree[rt].value=0; 23 if(l==r) return ; 24 int m=(l+r)>>1; 25 Build(rt<<1,l,m); 26 Build(rt<<1|1,m+1,r); 27 } 28 29 void Update(int rt,int num) 30 { 31 if(tree[rt].l==num&&tree[rt].r==num){ 32 tree[rt].value=1; 33 return ; 34 } 35 int m=(tree[rt].l+tree[rt].r)>>1; 36 if(num<=m) Update(rt<<1,num); 37 else Update(rt<<1|1,num); 38 tree[rt].value=tree[rt<<1].value+tree[rt<<1|1].value; 39 } 40 41 int Query(int rt,int l,int r) 42 { 43 /* 44 画个图就明白了,搜寻的区间为[l,r],m代表当前节点的左儿子和右儿子的分支 45 如果左儿子有包含该区间的元素,即l<=m,那么就要继续递归搜寻左儿子 46 如果右儿子有包含该区间的元素,即m<r,那么就要继续递归搜寻右儿子 47 当当前的节点的区间被搜寻的区间[l,r]覆盖的话,就说明该段区间完全在[l,r]里面 48 那么返回该节点的值 49 */ 50 if(l<=tree[rt].l&&tree[rt].r<=r){ 51 return tree[rt].value; 52 } 53 else{ 54 int m=(tree[rt].l+tree[rt].r)>>1; 55 int s1=0,s2=0; 56 if(l<=m) s1=Query(rt<<1,l,r); 57 if(r>m) s2=Query(rt<<1|1,l,r); 58 return s1+s2; 59 } 60 } 61 62 int main() 63 { 64 int n; 65 while(~scanf("%d",&n)){ 66 Build(1,1,n); 67 int sum=0; 68 for(int i=0;i<n;i++){ 69 scanf("%d",&a[i]); 70 a[i]++; 71 sum+=Query(1,a[i]+1,n); 72 Update(1,a[i]); 73 } 74 int res = sum; 75 for(int i=n-1;i>=0;i--){ 76 sum=sum-(n-a[i])+(a[i]-1); 77 if(sum<res) res=sum; 78 } 79 printf("%d\n",res); 80 } 81 return 0; 82 }
HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)
标签:
原文地址:http://www.cnblogs.com/fightfordream/p/5656675.html