叶子节点的权值两两不同,考虑线段树合并进行统计。
首先有一个显然的贪心策略:如果在某一个节点处,交换左右子树会使得这一棵子树内的逆序对个数更少,就一定要交换,因为现在交不交换对以后的状态不会产生影响。
然后我们考虑如何计算交换或者不交换的逆序对数量。对于一棵子树中的一个数来说,以它为右端的逆序对数就是另一棵子树中比它大的数,这类似于线段树中的查询前缀和的操作。这种统计操作也是线段树合并很擅长的。
具体代码段如下
int merge(int p , int q){ if(!p) return q; if(!q) return p; Tree[p].size += Tree[q].size; ans1 += 1ll * Tree[Tree[p].l].size * Tree[Tree[q].r].size; ans2 += 1ll * Tree[Tree[q].l].size * Tree[Tree[p].r].size; //ans1表示交换,ans2表示不交换 Tree[p].l = merge(Tree[p].l , Tree[q].l); Tree[p].r = merge(Tree[p].r , Tree[q].r); throwaway(q);//节点回收 return p; }
中间的ans1和ans2的统计应该也是不难理解的。
#include<bits/stdc++.h> #define mid ((l + r) >> 1) //This code is written by Itst using namespace std; inline int read(){ int a = 0; bool f = 0; char c = getchar(); while(c != EOF && !isdigit(c)){ if(c == '-') f = 1; c = getchar(); } while(c != EOF && isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ '0'); c = getchar(); } return f ? -a : a; } const int MAXN = 200010; struct node{ int l , r , size; }Tree[MAXN * 20]; int root[MAXN << 1] , N , cntNode , cnt; long long ans , ans1 , ans2; queue < int > trashbin; inline int allocate(){ if(trashbin.empty()) return ++cntNode; int t = trashbin.front(); trashbin.pop(); return t; } inline void throwaway(int now){ Tree[now].l = Tree[now].r = Tree[now].size = 0; trashbin.push(now); } void insert(int& now , int l , int r , int tar){ if(!now) now = allocate(); ++Tree[now].size; if(l != r) if(mid >= tar) insert(Tree[now].l , l , mid , tar); else insert(Tree[now].r , mid + 1 , r , tar); } int merge(int p , int q){ if(!p) return q; if(!q) return p; Tree[p].size += Tree[q].size; ans1 += 1ll * Tree[Tree[p].l].size * Tree[Tree[q].r].size; ans2 += 1ll * Tree[Tree[q].l].size * Tree[Tree[p].r].size; Tree[p].l = merge(Tree[p].l , Tree[q].l); Tree[p].r = merge(Tree[p].r , Tree[q].r); throwaway(q); return p; } void create(int now){ int t = read(); if(!t){ int p = ++cnt; create(p); root[now] = root[p]; create(p = ++cnt); merge(root[now] , root[p]); ans += min(ans1 , ans2); ans1 = ans2 = 0; } else insert(root[now] , 1 , N , t); } int main(){ #ifndef ONLINE_JUDGE freopen("3521.in" , "r" , stdin); //freopen("3521.out" , "w" , stdout); #endif N = read(); create(1); printf("%lld" , ans); return 0; }