标签:else sub update www 一个 bsp put pre htm
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 25092 Accepted Submission(s): 14816
第一题线段树题。
学习https://www.cnblogs.com/ziyi--caolu/archive/2013/01/15/2860768.html
题意:给出一列数,每次把最前面一个移动最后面,都是一个新的序列,要求计算最小的逆序数并输出。
题解:在输入的时候计算线段树中有多少是比当前的数大的,表示当前序列中由该数组成逆序数,用a[i]来保存,全部输入完之后就获得总的逆序数。然后开始把前面的的数一个个移到最后面,每次计算这个序列的逆序数(用a[i]来实现,代码里注释了),并更新一下最小逆序数。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 5005 4 struct node 5 { 6 int l,r; 7 int num; 8 }tree[4*N]; 9 void creat(int i,int l,int r) { 10 int mid=(l+r)/2; 11 tree[i].l=l; 12 tree[i].r=r; 13 tree[i].num=0; 14 if(l==r) { 15 return ; 16 } 17 creat(i*2,l,mid); 18 creat(i*2+1,mid+1,r); 19 } 20 void update(int i,int k) { 21 if(tree[i].l==k&&tree[i].r==k) { 22 tree[i].num=1; 23 return ; 24 } 25 int mid=(tree[i].l+tree[i].r)/2; 26 if(k<=mid) 27 update(i*2,k); 28 else 29 update(i*2+1,k); 30 tree[i].num=tree[i*2].num+tree[i*2+1].num; 31 } 32 int getsum(int i,int k,int n) {//统计线段树中大于k的有多少个 33 if(k<=tree[i].l&&tree[i].r<=n) { 34 return tree[i].num; 35 } else { 36 int mid=(tree[i].l+tree[i].r)/2; 37 int sum1=0,sum2=0; 38 if(k<=mid) 39 sum1=getsum(i*2,k,n); 40 if(n>mid) 41 sum2=getsum(i*2+1,k,n); 42 return sum1+sum2; 43 } 44 } 45 int a[N]; 46 int main() { 47 int n; 48 while(~scanf("%d",&n)) 49 { 50 memset(a,0,sizeof(a)); 51 creat(1,0,n-1);int ans=0; 52 for(int i=0;i<n;i++) 53 { 54 scanf("%d",&a[i]); 55 ans+=getsum(1,a[i]+1,n-1);//每次统计大于该数的有多少个 56 update(1,a[i]);//插入,更新结点 57 } 58 int minn=ans;//把全部输入完后,还没有移动过的逆序数赋给minn 59 for(int i=0;i<n;i++) 60 { 61 ans=ans+n-1-a[i]-a[i];//这里的a[i]表示可以和a[i]组合逆序的对数,每次把最前面的数移动最后面,就相当于 62 minn=min(minn,ans);//有a[i]对逆序不能成立了,但相应的增加了n-1-a[i]对逆序 63 } 64 printf("%d\n",minn); 65 } 66 return 0; 67 }
hdu1394Minimum Inversion Number(线段树,求最小逆序数)
标签:else sub update www 一个 bsp put pre htm
原文地址:https://www.cnblogs.com/fqfzs/p/9892396.html