初始对于每一个叶子节点建一棵权值线段树,然后再线段树合并时计算一下两者分别在前面和后面的代价,$ans+=min(\sum sz[rz[x]]\cdot sz[ls[y]],\sum sz[ls[x]]\cdot sz[rs[y]])$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define N 200001 5 #define mid (l+r>>1) 6 int V,n,ls[N*20],rs[N*20]; 7 ll ans,ans1,ans2,sz[N*20]; 8 void update(int k,int l,int r,int x){ 9 sz[k]=1; 10 if (l==r)return; 11 if (x<=mid)update(ls[k]=++V,l,mid,x); 12 else update(rs[k]=++V,mid+1,r,x); 13 } 14 int merge(int x,int y){ 15 if (x*y==0)return x+y; 16 if (ls[x]+rs[x]==0)sz[x]+=sz[y]; 17 else{ 18 ans1+=sz[ls[x]]*sz[rs[y]]; 19 ans2+=sz[rs[x]]*sz[ls[y]]; 20 sz[x]=sz[ls[x]=merge(ls[x],ls[y])]+sz[rs[x]=merge(rs[x],rs[y])]; 21 } 22 return x; 23 } 24 int dfs(){ 25 int x,r,r1=0,r2=0; 26 scanf("%d",&x); 27 if (x){ 28 update(r=++V,1,n,x); 29 return r; 30 } 31 r1=dfs(); 32 r2=dfs(); 33 ans1=ans2=0; 34 r=merge(r1,r2); 35 ans+=min(ans1,ans2); 36 return r; 37 } 38 int main(){ 39 scanf("%d",&n); 40 dfs(); 41 printf("%lld",ans); 42 }