线段树合并入门题。
分别计算左子树的逆序对,右子树的逆序对,合并的时候计算贡献。
1 #include<bits/stdc++.h> 2 #define N 8000005 3 using namespace std; 4 typedef long long ll; 5 int n,sz,tot,cnt=0; 6 ll cnt1,cnt2,ans; 7 int val[N],ls[N],rs[N],rt[N],sumv[N],l[N],r[N]; 8 inline int read(){ 9 int f=1,x=0;char ch; 10 do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); 11 do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); 12 return f*x; 13 } 14 void intree(int x){ 15 val[x]=read(); 16 if(!val[x]){ 17 l[x]=++cnt;intree(l[x]); 18 r[x]=++cnt;intree(r[x]); 19 } 20 } 21 inline void pushup(int o){sumv[o]=sumv[ls[o]]+sumv[rs[o]];} 22 void build(int &o,int l,int r,int v){ 23 if(!o)o=++cnt;if(l==r){sumv[o]=1;return;} 24 int mid=(l+r)>>1; 25 if(v<=mid)build(ls[o],l,mid,v); 26 else build(rs[o],mid+1,r,v); 27 pushup(o); 28 } 29 int merge(int x,int y){ 30 if(!x)return y;if(!y)return x; 31 cnt1+=(ll)sumv[rs[x]]*sumv[ls[y]]; 32 cnt2+=(ll)sumv[ls[x]]*sumv[rs[y]]; 33 ls[x]=merge(ls[x],ls[y]); 34 rs[x]=merge(rs[x],rs[y]); 35 pushup(x);return x; 36 } 37 void solve(int x){ 38 if(!x)return; 39 solve(l[x]);solve(r[x]); 40 if(!val[x]){ 41 cnt1=cnt2=0; 42 rt[x]=merge(rt[l[x]],rt[r[x]]); 43 ans+=min(cnt1,cnt2); 44 } 45 } 46 int main(){ 47 n=read();cnt++; 48 intree(1); 49 for(int i=1;i<=cnt;i++)if(val[i])build(rt[i],1,n,val[i]); 50 solve(1); 51 printf("%lld ",ans); 52 return 0; 53 }