バイナリツリーを考えると、リーフノードは、値が前葉の先行順走査が起こっ逆にするように、息子のノードの動作を中心に、数回交換することができるしています。
ツリーノードを考えてみましょ生成する逆に噴火:
①左のサブツリーでのみ生産。
②右のサブツリーでのみ生産。
CROSSは、③左部分木と右のサブツリーを生成します。
そのため、二分木の性質上、これだけ①②両方のケースを解決するための再帰は、ちょうど③状況を考えます。
記録情報に重みツリーラインでは、セグメントツリーで答えをカウントするマージ。
具体的な実装の詳細は、コードを確認してください。
開くことを忘れないでください\(ロング\ロング\) 。
\(コード:\)
#include<bits/stdc++.h>
#define maxn 10000010
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,root,tree_cnt;
ll s1,s2,ans;
bool vis[maxn];
int ls[maxn],rs[maxn],rt[maxn];
ll siz[maxn];
void pushup(int cur)
{
siz[cur]=siz[ls[cur]]+siz[rs[cur]];
}
void modify(int L,int R,int pos,int &cur)
{
if(!cur) cur=++tree_cnt;
if(L==R)
{
siz[cur]++;
return;
}
int mid=(L+R)>>1;
if(pos<=mid) modify(L,mid,pos,ls[cur]);
if(pos>mid) modify(mid+1,R,pos,rs[cur]);
pushup(cur);
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
s1+=siz[ls[x]]*siz[rs[y]];
s2+=siz[ls[y]]*siz[rs[x]];
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
pushup(x);
return x;
}
void dfs(int &x)
{
int val;
read(val);
x=++tree_cnt;
if(!val) dfs(ls[x]),dfs(rs[x]);
else vis[x]=true,modify(1,n,val,rt[x]);
}
void work(int x)
{
if(vis[x]) return;
work(ls[x]),work(rs[x]),s1=s2=0;
rt[x]=merge(rt[ls[x]],rt[rs[x]]);
ans+=min(s1,s2);
}
int main()
{
read(n);
dfs(root);
work(root);
printf("%lld\n",ans);
return 0;
}