点击打开链接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 1010 int 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 1010 int 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; }