bzoj3702/bzoj2212 二叉树 (线段树合并)
用线段树记每个子树中包含的数,然后合并的时候算出来逆序对的数量(合并a,b时,就是size[ch[a][1]]*size[ch[b][0]]),来决定这个子树要不要翻转
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=2e5+10,logn=1e7; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int siz[logn],ch[logn][2],pct; 16 int N; 17 ll ans; 18 19 void insert(int &p,int l,int r,int x){ 20 if(!p) p=++pct; 21 siz[p]++; 22 if(l==r) return; 23 int m=l+r>>1; 24 if(x<=m) insert(ch[p][0],l,m,x); 25 else insert(ch[p][1],m+1,r,x); 26 } 27 28 ll merge(int &a,int b,int l,int r){ 29 if(!b) return 0; 30 if(!a){a=b;return 0;} 31 siz[a]+=siz[b]; 32 if(l==r) return 0; 33 ll re=1ll*siz[ch[a][1]]*siz[ch[b][0]]; 34 int m=l+r>>1; 35 re+=merge(ch[a][0],ch[b][0],l,m); 36 re+=merge(ch[a][1],ch[b][1],m+1,r); 37 return re; 38 } 39 40 int dfs(){ 41 int x=rd(); 42 if(x!=0){ 43 int rt=0; 44 insert(rt,1,N,x); 45 return rt; 46 } 47 int lc=dfs(),rc=dfs(); 48 ll sm=1ll*siz[lc]*siz[rc]; 49 if(siz[lc]>siz[rc]) swap(lc,rc); 50 ll re=merge(lc,rc,1,N); 51 ans+=min(re,sm-re); 52 return lc; 53 } 54 55 int main(){ 56 //freopen(".in","r",stdin); 57 int i,j,k; 58 N=rd(); 59 dfs(); 60 printf("%lld\n",ans); 61 return 0; 62 }