题目描述:
qwq…
题目分析:
一棵树中的逆序对个数=左子树的+右子树的+跨越形成的
我们只要比较一下交换之后和之前跨越的逆序对个数,取小即可…
权值线段树+线段树合并
题目链接:
Ac 代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#define int long long
const int maxm=4000005;
int val[maxm],root[maxm],ls[maxm],rs[maxm],lc[maxm],rc[maxm],sum[maxm];
int sz,rt,Rt,n,ans1,ans2;
void insert(int &now,int l,int r,int ind)
{
if(!now) now=++rt;
if(l>=r)
{
sum[now]=1;
return;
}
int mid=(l+r)>>1;
ind<=mid?insert(lc[now],l,mid,ind):insert(rc[now],mid+1,r,ind);
sum[now]=sum[lc[now]]+sum[rc[now]];
}
void build(int &now)
{
if(!now) now=++sz;
scanf("%lld",&val[now]);
if(!val[now]) build(ls[now]),build(rs[now]);
else insert(root[now],1,n,val[now]);
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
ans1+=sum[lc[x]]*sum[rc[y]];
ans2+=sum[rc[x]]*sum[lc[y]];
lc[x]=merge(lc[x],lc[y]);
rc[x]=merge(rc[x],rc[y]);
sum[x]=sum[lc[x]]+sum[rc[x]];
return x;
}
int solve(int now)
{
if(val[now]) return 0;
int Ans=solve(ls[now])+solve(rs[now]);
ans1=0,ans2=0;
root[now]=merge(root[ls[now]],root[rs[now]]);
return Ans+std::min(ans1,ans2);
}
signed main()
{
scanf("%lld",&n);
build(Rt);
printf("%lld\n",solve(Rt));
return 0;
}