Minimum Inversion Number
Topic link: HDU-1394There are many ways to find the inverse ordinal, one can be directly violent, the complexity of O(n^2), the second can be found by merge sort, the complexity of O(nlogn), and
now I have learned the line segment The tree can also be calculated by the line segment tree, the complexity of O(nlogn);
the first two methods will not be discussed, but only the method of using the segment tree to find the inverse number;
9 2 8 3 6 7 5 The inverse number of this sequence It's 12, how did it come out?
Look at 9 first, there is no larger number in front, contribute 0,
2, there is a larger number in front, contribute 1,
8, contribute 1; 3 contribute 2; 6 contribute 2; 7 contribute 2; 5 contribute 4, A total of 12;
it can be seen that it is only necessary to find out how many numbers larger than him have been written before writing each number;
we can first build an empty line segment tree, the nodes are 1~n, and each write Before the next number, check the position of the number and how many numbers are written after it, and then record the number;
this question requires to find out what is the smallest inverse number in the given sequence in different order, such as 2 8 7 4 3 Different permutations can be 8 7 4 3 2 or 7 4 3 2 8. . . . . .
If a sequence is 0~n-1:
when a number i is at the beginning of the sequence, there are only i numbers smaller than it in the sequence, and when it moves to the end of the sequence, there are ni-1 numbers in front of it that are much larger than it ;
so the reverse number of each transfer changes to sum=sum-i+n-1-i;
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 5010; int n; int a[maxn]; struct node{ int left, right, x; }tree[maxn<<2]; void build(int m, int l, int r){ tree[m].left=l; tree[m].right=r; if(l==r){ tree[m].x=0; return; } int mid=(l+r)>>1; build(m<<1, l, mid); build(m<<1|1, mid+1, r); tree[m].x=tree[m<<1].x+tree[m<<1|1].x; } void update(int m, int a){ if(tree[m].left==a&&tree[m].right==a){ tree[m].x++; return; } int mid=(tree[m].left+tree[m].right)>>1; if(a<=mid) update(m<<1, a); else update(m<<1|1, a); tree[m].x=tree[m<<1].x+tree[m<<1|1].x; } int query(int m, int l, int r){ if(tree[m].left==l&&tree[m].right==r){ return tree[m].x; } int sum1=0, sum2=0; int mid=(tree[m].left+tree[m].right)>>1; if(r<=mid) return query(m<<1, l, r); else if(l>mid) return query(m<<1|1, l, r); return query(m<<1, l, mid)+query(m<<1|1, mid+1, r); } int cnt[maxn], sum=0; int main(){ while(~scanf("%d", &n)){ build(1, 1, n); sum=0; for(int i=1; i<=n; i++){ scanf("%d", &a[i]); sum+=query(1, a[i]+1, n);//Query first and then update; because the input value is 0~n-1, and the node value is 1~n, so it is one position backward; update(1, a[i]+1); } int ans = sum; for(int i=1; i<=n; i++){ //printf("i:%d sum:%d\n", i, sum); sum=sum-a[i]+n-a[i]-1; years=min(years, sum); } printf("%d\n", ans); } return 0; }