[bzoj3702] 二叉树
一个节点的儿子是否交换,不会影响到它和兄弟节点间的逆序对数。
所以每次合并线段树的时候算一下交换与不交换的逆序对数,然后选个较小值就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define ll long long 7 using namespace std; 8 const int maxn=400233,mxnode=200233*20; 9 int lc[mxnode],rc[mxnode],sz[mxnode],tot; 10 int ls[maxn],rs[maxn],size[maxn],mp[maxn],tt,rt[maxn]; 11 int i,j,k,n,m,presz,P,id,root; 12 ll num0,num1,ans; 13 14 int ra;char rx; 15 inline int read(){ 16 rx=getchar(),ra=0; 17 while(rx<'0'||rx>'9')rx=getchar(); 18 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 19 } 20 21 int merge(int a,int b){ 22 if(!b){presz+=sz[a];return a;} 23 if(!a){num0+=1LL*sz[b]*presz;return b;} 24 sz[a]+=sz[b]; 25 rc[a]=merge(rc[a],rc[b]),lc[a]=merge(lc[a],lc[b]); 26 return a; 27 } 28 void build(int &x,int a,int b){ 29 x=++tot,sz[x]=1; 30 if(a==b)return; 31 int mid=a+b>>1; 32 if(P<=mid)build(lc[x],a,mid);else build(rc[x],mid+1,b); 33 } 34 void in(int &x){ 35 x=++tt,id=read(); 36 if(id)mp[x]=id,size[x]=1;else 37 in(ls[x]),in(rs[x]),size[x]=size[ls[x]]+size[rs[x]]; 38 } 39 void dfs(int x){ 40 if(size[x]==1){P=mp[x],build(rt[x],1,n);return;} 41 dfs(ls[x]),dfs(rs[x]), 42 presz=num0=0,rt[x]=merge(rt[ls[x]],rt[rs[x]]); 43 num1=1LL*size[ls[x]]*size[rs[x]]-num0; 44 // printf(" %d %lld %lld\n",x,num0,num1); 45 ans+=min(num0,num1); 46 } 47 int main(){ 48 n=read(); 49 in(root);//printf("cnt: %d\n",cnt); 50 dfs(1); 51 printf("%lld\n",ans); 52 return 0; 53 }