求Inversion的最小逆序数
先用线段树求出初序列的逆序数,
然后 每次将最后一个数,移到第一个位置
逆序数的变化 减少a[i], 增加n - 1 - a[i]
记录最小逆序数
update:单点增减 query:区间求和
#include <cstdio> #include <cstring> using namespace std; #define LL(x) (x<<1) #define RR(x) (x<<1|1) const int maxn = 5005; struct node { int l, r; int sum; }tree[maxn*4]; int a[maxn]; void build(int rt, int l, int r) { tree[rt].l = l; tree[rt].r = r; tree[rt].sum = 0; if(tree[rt].l == tree[rt].r) { return ; } int mid = (tree[rt].l + tree[rt].r)>>1; build(LL(rt), l, mid); build(RR(rt), mid+1, r); } void update(int rt, int pos) { if(tree[rt].l == tree[rt].r) { tree[rt].sum += 1; return ; } int mid = (tree[rt].l + tree[rt].r)>>1; if(pos <=mid) update(LL(rt), pos); else update(RR(rt), pos); tree[rt].sum = tree[LL(rt)].sum + tree[RR(rt)].sum; } int query(int rt, int l, int r) { if(l <= tree[rt].l && tree[rt].r <= r) { return tree[rt].sum; } int mid = (tree[rt].l + tree[rt].r)>>1; int ret = 0; if(l <= mid) ret += query(LL(rt), l, r); if(r > mid) ret += query(RR(rt), l, r); return ret; } int main() { int n, i, ret, sum; while(scanf("%d",&n)!=EOF) { build(1, 0, n-1); sum = 0; for(i=0; i<n; ++i) { scanf("%d",&a[i]); sum += query(1, a[i], n-1); update(1,a[i]); } ret = sum; for(i=0; i<n-1; ++i) { ret += n- a[i] - a[i] - 1; if(sum > ret) sum = ret; } printf("%d\n", sum); } return 0; }