hdu1394 Minimum Inversion Number ——线段树入门题
2013-04-23 23:23
351 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394
题目大意:
给一个数字由0~n-1这n个数字组成的数列,不断地把第一个数字移动到最后,一共得到n个数列。求这n个数列中,逆序数最小是多少。
题目思路:
首先,建一棵线段树,每个节点表示这个区间内已经插入的数字的个数,开始初始化为0.然后没读入一个数字,把这个数字插入得到线段树的叶子节点,然后向上更新父节点。这样,在建树的过程中,就可以统计出每个逆序数,也就是说,可以再插入每个数字的时候,查找已经插入的数字当中,比这个数字大的数字有多少个,直到最后就可以求出这个数列的逆序数。
然后,利用数列的性质。因为每次都是把第一个数字移动到最后,比如这个数字是a,那么显然,比这个数字小的有a个,比这个数字大的有n-1-a个;因为这个数字在最前面,所以当前这个数字的逆序数是a,把这个数字移动到最后之后,这个数字的逆序数是n-1-a,逆序数增加量:n-1-a-a。这样就可以由原来的数列的逆序数求出所有数列的逆序数。好神奇~
现在写点更新的线段树比以前熟练一点了~接下来练区间更新的。
题目大意:
给一个数字由0~n-1这n个数字组成的数列,不断地把第一个数字移动到最后,一共得到n个数列。求这n个数列中,逆序数最小是多少。
题目思路:
首先,建一棵线段树,每个节点表示这个区间内已经插入的数字的个数,开始初始化为0.然后没读入一个数字,把这个数字插入得到线段树的叶子节点,然后向上更新父节点。这样,在建树的过程中,就可以统计出每个逆序数,也就是说,可以再插入每个数字的时候,查找已经插入的数字当中,比这个数字大的数字有多少个,直到最后就可以求出这个数列的逆序数。
然后,利用数列的性质。因为每次都是把第一个数字移动到最后,比如这个数字是a,那么显然,比这个数字小的有a个,比这个数字大的有n-1-a个;因为这个数字在最前面,所以当前这个数字的逆序数是a,把这个数字移动到最后之后,这个数字的逆序数是n-1-a,逆序数增加量:n-1-a-a。这样就可以由原来的数列的逆序数求出所有数列的逆序数。好神奇~
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <stack> #include <queue> #include <map> #include <set> #include <vector> #include <cmath> #include <algorithm> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; typedef long long int LL; const int MAXN = 0x3f3f3f3f; const int MIN = -0x3f3f3f3f; const double eps = 1e-9; const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1}, {1,1},{1,-1},{-1,-1}}; const int MAX = 5000+10; int a[MAX<<2], n, b[MAX]; void pushup(int rt) { a[rt] = a[rt<<1] + a[rt<<1|1]; } void build(int l, int r, int rt) { if (l == r) { a[rt] = 0; return; } int m = (l + r) >> 1; build(lson); build(rson); pushup(rt); } void update(int p, int l, int r, int rt) { if (l == r) { a[rt]++; return; } int m = (l + r) >> 1; if (p <= m) update(p, lson); else update(p, rson); pushup(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && R >= r) { return a[rt]; } int m = (l + r) >> 1, ret = 0; if (L <= m) ret += query(L, R, lson); if (R > m) ret += query(L, R, rson); return ret; } int main(void){ #ifndef ONLINE_JUDGE freopen("hdu1394.in", "r", stdin); #endif while (~scanf("%d", &n)){ int i, j, sum; build(0, n - 1, 1); sum = 0; for (i = 0; i < n; ++i){ scanf("%d", b + i); sum += query(b[i]+1, n - 1, 0, n - 1, 1); update(b[i], 0, n - 1, 1); } int ans = sum; for (i = 0; i < n; ++i){ sum += (n - 1 - b[i] * 2); ans = min(ans, sum); } printf("%d\n", ans); } return 0; }
现在写点更新的线段树比以前熟练一点了~接下来练区间更新的。
相关文章推荐
- 线段树专辑——hdu 1394 Minimum Inversion Number
- HDU-1394 Minimum Inversion Number (逆序数,线段树或树状数组)
- hdu 1394 Minimum Inversion Number -求逆序对的个数- 线段树单节点更新
- HDU 1394 Minimum Inversion Number (暴力+线段树)
- 【HDU】1394 Minimum Inversion Number(线段树求逆序数)
- hdu 1394 Minimum Inversion Number(线段树单点更新)
- [HDU] 1394 Minimum Inversion Number [线段树求逆序数]
- HDU 1394 Minimum Inversion Number(线段树求逆序对数目)
- 线段树专题#5_蒟蒻训练历程记录_HDU 1394 Minimum Inversion Number_单点更新+思维转换
- HDU 1394 Minimum Inversion Number(线段树的单点更新)
- 线段树单点更新 HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number.(线段树)
- hdu1394 Minimum Inversion Number (线段树
- hdu-1394 Minimum Inversion Number(线段树求逆序数模板)
- HDU 1394 Minimum Inversion Number (线段树 单点更新 求逆序数)
- HDU 1394 Minimum Inversion Number【线段树求逆序数】
- HDU 1394 Minimum Inversion Number( 归并排序 & 线段树 )
- HDU 1394 Minimum Inversion Number(线段树求逆序数啊)
- 【HDU 1394】Minimum Inversion Number 【线段树 训练2】
- ZOJ 1484 HDU 1394 Minimum Inversion Number / 线段树单点更新