题目大意:
一棵二叉树,所有非叶子节点都有两个孩子
在每个叶子节点上有一个权值 可以任意交换每个非叶子节点的左右孩子
要求进行一系列交换,使得最终所有叶子节点的权值按照顺序写出来,逆序对个数最少
思路:
建立权值线段树
dfs时 对于每个节点 判断交换更好还是不交换好 再加上左右儿子的答案向上继续传递答案
判断的时候merge
1 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<algorithm> 8 #include<vector> 9 #include<queue> 10 #define inf 2139062143 11 #define ll long long 12 #define MAXN 400100 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,o,rt[MAXN],tot,ch[MAXN][2],val[MAXN],ls[MAXN<<5],rs[MAXN<<5]; 22 ll ansl,ansr,sum[MAXN<<5]; 23 void init(int &x) 24 { 25 if(!x) x=++tot; 26 val[x]=read(); 27 if(!val[x]) {init(ch[x][0]);init(ch[x][1]);} 28 } 29 void mdf(int &k,int l,int r,int x) 30 { 31 k=++tot; 32 if(l==r) {sum[k]=1;return ;} 33 int mid=(l+r)>>1; 34 if(x<=mid) mdf(ls[k],l,mid,x); 35 else mdf(rs[k],mid+1,r,x); 36 sum[k]=sum[ls[k]]+sum[rs[k]]; 37 } 38 int merge(int a,int b) 39 { 40 if(!a||!b) return a+b; 41 ansl+=sum[rs[a]]*sum[ls[b]]; 42 ansr+=sum[ls[a]]*sum[rs[b]]; 43 ls[a]=merge(ls[a],ls[b]); 44 rs[a]=merge(rs[a],rs[b]); 45 sum[a]=sum[ls[a]]+sum[rs[a]]; 46 return a; 47 } 48 ll dfs(int x) 49 { 50 ll res=0; 51 if(!val[x]) 52 { 53 res=dfs(ch[x][0])+dfs(ch[x][1]); 54 ansl=ansr=0; 55 rt[x]=merge(rt[ch[x][0]],rt[ch[x][1]]); 56 res+=min(ansl,ansr); 57 } 58 else mdf(rt[x],1,n,val[x]); 59 return res; 60 } 61 int main() 62 { 63 n=read(); 64 init(o);tot=0; 65 printf("%lld",dfs(1)); 66 }