题解:

线段树合并

比较一下哪一种方案的逆序对少

代码:

#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);  
}  

 

posted on 2017-12-23 08:55  宣毅鸣  阅读(95)  评论(0编辑  收藏  举报