题目
思路
对于每个点,看两种方式哪种的逆序对数更少。
线段树合并。
维护值域线段树,每个点的时候,左右的线段树合并。
如果合并时只有一颗非空了就直接结束。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+77;
int n,cnt;
ll ans,u,v;
struct Seg
{
int ls,rs,size;
}tr[22*N];
int ins(int l,int r,int val)
{
int yjy=++cnt;
tr[yjy].size++;
if(l==r) return yjy;
int mid=(l+r)>>1;
if(val<=mid) tr[yjy].ls=ins(l,mid,val);
else tr[yjy].rs=ins(mid+1,r,val);
return yjy;
}
int merge(int p,int q,int l,int r)
{
if(!q||!p) return (!p)?q:p;
if(l==r)
{
tr[p].size+=tr[q].size; return p;
}
u+=(ll)tr[tr[p].rs].size*tr[tr[q].ls].size;
v+=(ll)tr[tr[p].ls].size*tr[tr[q].rs].size;
int mid=(l+r)>>1;
tr[p].ls=merge(tr[p].ls,tr[q].ls,l,mid);
tr[p].rs=merge(tr[p].rs,tr[q].rs,mid+1,r);
tr[p].size=tr[tr[p].ls].size+tr[tr[p].rs].size;
return p;
}
int dfs()
{
int yjy,val;
scanf("%d",&val);
if(val==0)
{
int ls=dfs(),rs=dfs();
u=0;v=0;
yjy=merge(ls,rs,1,n);
ans+=min(u,v);
}
else yjy=ins(1,n,val);
return yjy;
}
int main()
{
scanf("%d",&n);
dfs();
printf("%lld",ans);
}