题解:
线段树合并
比较一下哪一种方案的逆序对少
代码:
#include<bits/stdc++.h> using namespace std; const int N=4000005; typedef long long ll; ll ans,ANS,a[N],cnt,ch[N][2],rt[N],cn,CH[N][2],sum[N],CNT,n; void addnew(ll &x,ll l,ll r,ll v) { CNT++;x=CNT; sum[x]++; if (l==r) return; ll mid=(l+r)/2; if (v<=mid) addnew(ch[x][0],l,mid,v); else addnew(ch[x][1],mid+1,r,v); } void build(ll &x) { cnt++;x=cnt; scanf("%lld",&a[x]); if (a[x]) { addnew(rt[x],1,n,a[x]); return; } build(CH[x][0]); build(CH[x][1]); } ll merge(ll x,ll y) { if (!x) return y; if (!y) return x; ans+=sum[ch[x][0]]*sum[ch[y][1]]; ch[x][0]=merge(ch[x][0],ch[y][0]); ch[x][1]=merge(ch[x][1],ch[y][1]); sum[x]=sum[ch[x][0]]+sum[ch[x][1]]; return x; } void dfs(ll x) { ll lc=CH[x][0],rc=CH[x][1]; if (a[x]) return; dfs(lc);dfs(rc); ll tot=sum[rt[lc]]*sum[rt[rc]]; ans=0; rt[x]=merge(rt[lc],rt[rc]); ANS+=min(ans,tot-ans); } int main() { scanf("%lld",&n); ll root; build(root); dfs(root); printf("%lld",ANS); }