hdu 2689 Sort it

来源:互联网 发布:新华网数据新闻 编辑:程序博客网 时间:2024/06/04 18:16

点击打开链接hdu2689


思路:线段树+单点更新
分析:
1 题目给定n个数要求最少的交换次数使得序列有序
2 显然两个数要交换肯定是满足i < j && num[i] > num[j]。那么假设现在读入一个数num[i],我们要求这个数num[i]要和前面的交换几次使得序列有序,就是查找num[0]~num[i-1]之间比num[i]大的数的个数,那么这个过程我们就可以利用线段树的查找,我们只要去查找[num[i]+1 , n]这个区间已经插入的个数即可,然后更新线段树
3 注意当num[i] == n的时候不用查找,直接更新

4 题目给定n 最大为1000,那么最话的情况下次数是1+2+3+...n,那么会超过int

代码:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define MAXN 1010int n;struct Node{   int left;   int right;   int num;};Node node[4*MAXN];//建立一颗空的线段树void buildTree(int left , int right , int pos){   node[pos].left = left;   node[pos].right = right;   node[pos].num = 0;   if(left == right)     return;   int mid = (left+right)>>1;   buildTree(left , mid , pos<<1);   buildTree(mid+1 , right , (pos<<1)+1);   node[pos].num = node[pos<<1].num + node[(pos<<1)+1].num;}//询问int query(int left , int right , int pos){   if(node[pos].left == left && node[pos].right == right)      return node[pos].num;   int mid = (node[pos].left + node[pos].right)>>1;   if(right <= mid)      return query(left , right , pos<<1);   else if(left > mid)      return query(left , right , (pos<<1)+1);   else      return query(left , mid , pos<<1)+query(mid+1 , right , (pos<<1)+1);}//更新void update(int index , int pos){   if(node[pos].left == node[pos].right){      node[pos].num++;      return;   }   int mid = (node[pos].left + node[pos].right)>>1;   if(index <= mid)     update(index , pos<<1);   else     update(index , (pos<<1)+1);   node[pos].num = node[pos<<1].num+node[(pos<<1)+1].num;}int main(){   int x , ans;   while(scanf("%d" , &n) != EOF){      buildTree(1 , n , 1);      ans = 0;      for(int i = 1 ; i <= n ; i++){         scanf("%d" , &x);         if(x != n)           ans += query(x+1 , n , 1);         update(x , 1);      }      printf("%d\n" , ans);   }   return 0;}



思路:树状数组
分析:
1 题目给定n个数要求最少的交换次数使得序列有序序列
2 显然两个数要交换肯定是满足i < j && num[i] > num[j]。那么假设现在读入一个数num[i],我们要求这个数num[i]要和前面的交换几次使得序列有序,就是查找num[0]~num[i-1]之间比num[i]大的数的个数。那么如果我们用树状数组来做的话,读入num[i]的时候我们应该查找前i-1个数比num[i]大的数,那么个数就是i-1-getSum(x-1),当x为1的时候就是i-1。最后更新树状数组。(这里原数组A[I]表示的是i是否插入,A[i]的值只有0/1两种!

3 题目给定n 最大为1000,那么最话的情况下次数是1+2+3+...n,那么会超过int


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 1010int num[MAXN];int C[MAXN];int lowbit(int x){   return x&(-x);}int getSum(int x){   int sum = 0;   while(x > 0){      sum += C[x];      x -= lowbit(x);   }   return sum;}void update(int x){   while(x <= MAXN){      C[x] += 1;      x += lowbit(x);   }}int main(){   int x , ans , n;   while(scanf("%d" , &n) != EOF){      memset(num , 0 , sizeof(num));      memset(C , 0 , sizeof(C));      ans = 0;      for(int i = 1 ; i <= n ; i++){         scanf("%d" , &x);            if(x > 1)           ans += i-1-getSum(x-1);         else           ans += i-1;         update(x);//更新树状数组      }      printf("%d\n" , ans);   }   return 0;}








原创粉丝点击