题解:
傻逼题
启发式合并线段树里面查$nlog^2$
线段树合并顺便维护一下$nlogn$
注意是叶子为n 总结点2n
代码:
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for(int i=h;i<=t;i++) #define dep(i,t,h) for(int i=t;i>=h;i--) #define ll long long #define me(x) memset(x,0,sizeof(x)) #define mep(x,y) memcpy(x,y,sizeof(y)) #define mid (t<=0?(h+t-1)/2:(h+t)/2) namespace IO{ char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T> void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } char sr[1<<24],z[20]; int Z,C1=-1; template<class T>void wer(T x) { if (x<0) sr[++C1]='-',x=-x; while (z[++Z]=x%10+48,x/=10); while (sr[++C1]=z[Z],--Z); } IL void wer1() { sr[++C1]=' '; } IL void wer2() { sr[++C1]=' '; } template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;} template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} template<class T>IL T MAX(T x,T y){return x>y?x:y;} template<class T>IL T MIN(T x,T y){return x<y?x:y;} }; using namespace IO; const int N1=4.1e5; const int N2=7e6; int ch[N1][2],node,v[N1],rt[N1],n; ll ans,cnt1,cnt2; int gettree() { int x,u=++node;read(x); if(!x)ch[u][0]=gettree(),ch[u][1]=gettree(); else v[u]=x; return u; } struct sgt{ int sum[N2],ls[N2],rs[N2],cnt; void insert(int &x,int h,int t,int pos) { x=++cnt; sum[x]=1; if (h==t) return; if (pos<=mid) insert(ls[x],h,mid,pos); else insert(rs[x],mid+1,t,pos); } int merge(int x,int y) { if (!x||!y) return x^y; sum[x]+=sum[y]; cnt1+=1ll*sum[ls[x]]*sum[rs[y]]; cnt2+=1ll*sum[rs[x]]*sum[ls[y]]; ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); return x; } }S; void dfs(int x) { if (v[x]) { S.insert(rt[x],1,n,v[x]); return; } dfs(ch[x][0]); dfs(ch[x][1]); cnt1=0,cnt2=0; rt[x]=S.merge(rt[ch[x][0]],rt[ch[x][1]]); ans+=MIN(cnt1,cnt2); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); gettree(); dfs(1); cout<<ans<<endl; return 0; }