HDU 1394 & ZOJ 1484 Minimum Inversion Number
2014-04-11 14:05
295 查看
(更新点查询区间)
这题重在想到,写代码很容易了。。这题是利用线段树求逆序数,不按给定的顺序建树,而是有序地插入。比如每插入一个数,就统计之前插入的那些数里比他大的有多少个,这个数就是此时的逆序数,然后累加每个的逆序数,就是整个原始序列的逆序数,怎么统计呢?前面说了,是有序的插入,查询比它大的数岂不是查它右边就好了?即查询a[i]~n-1中插入了多少数,凡插入了的即是比他大的。这样,总的逆序数就出来了。现在求一个最小值。这里有个结论,因为每次都把第一个移到最后即可,考虑第一个元素,x[0]是此时的逆序数,把x[0]放到最后,这时要增加原来比a[0]大的个数(即n-a[0]-1个)个逆序数,同时要减少a[0]个逆序数,因为放到后面去了,前面的那些比它小的数(a[0]个)不再构成逆序数。这是即 sum = sum + n - a[i] - 1 - a[i] ,跑一边循环求最小值。。感觉自己也没说清楚,还是不懂的自己体会一下吧。
代码:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
View Code
这题重在想到,写代码很容易了。。这题是利用线段树求逆序数,不按给定的顺序建树,而是有序地插入。比如每插入一个数,就统计之前插入的那些数里比他大的有多少个,这个数就是此时的逆序数,然后累加每个的逆序数,就是整个原始序列的逆序数,怎么统计呢?前面说了,是有序的插入,查询比它大的数岂不是查它右边就好了?即查询a[i]~n-1中插入了多少数,凡插入了的即是比他大的。这样,总的逆序数就出来了。现在求一个最小值。这里有个结论,因为每次都把第一个移到最后即可,考虑第一个元素,x[0]是此时的逆序数,把x[0]放到最后,这时要增加原来比a[0]大的个数(即n-a[0]-1个)个逆序数,同时要减少a[0]个逆序数,因为放到后面去了,前面的那些比它小的数(a[0]个)不再构成逆序数。这是即 sum = sum + n - a[i] - 1 - a[i] ,跑一边循环求最小值。。感觉自己也没说清楚,还是不懂的自己体会一下吧。
代码:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <utility> #include <cstdlib> using namespace std; #define N 5010 int tree[4*N]; int a ; void build(int l,int r,int rt) { tree[rt] = 0; if(l == r) { return; } int mid = (l+r)/2; build(l,mid,2*rt); build(mid+1,r,2*rt+1); } void update(int l,int r,int pos,int rt) { if(l == r) { tree[rt]++; return; } int mid = (l+r)/2; if(pos<=mid) update(l,mid,pos,2*rt); else update(mid+1,r,pos,2*rt+1); tree[rt] = tree[2*rt]+tree[2*rt+1]; } int query(int l,int r,int aa,int bb,int rt) { if(aa>r||bb<l) return 0; if(aa<=l&&bb>=r) return tree[rt]; int mid = (l+r)/2; int res = 0; if(aa<=mid) res += query(l,mid,aa,bb,2*rt); if(bb>mid) res += query(mid+1,r,aa,bb,2*rt+1); return res; } int main() { int n,i; int sum; while(scanf("%d",&n)!=EOF) { build(0,n-1,1); sum = 0; for(i=0;i<n;i++) { scanf("%d",&a[i]); sum += query(0,n-1,a[i],n-1,1); update(0,n-1,a[i],1); } int ans = 100000000; for(i=0;i<n;i++) { sum = sum+n-a[i]-1-a[i]; ans = min(ans,sum); } printf("%d\n",ans); } return 0; }
View Code
相关文章推荐
- HDU 1394 & ZOJ 1484 Minimum Inversion Number
- zoj 1484 || hdu 1394 Minimum Inversion Number
- ZOJ 1484 HDU 1394 Minimum Inversion Number / 线段树单点更新
- [逆序对] 入门 — [HDU] 1394 - Minimum Inversion Number & [HDU] 4911 - Inversion
- 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(单点更新)
- HDU1394--Minimum Inversion Number
- 树状数组求逆序数 HDU-1394 Minimum Inversion Number
- HDU 1394-Minimum Inversion Number(BIT)
- hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number(线段树)
- hdu 1394 Minimum Inversion Number 求逆序数(树状数组/归并排序/暴力)
- hdu 1394 Minimum Inversion Number(线段树)
- hdu1394-Minimum Inversion Number(线段树)
- hdu1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number(线段树:单点更新,区间求和)