3702: 二叉树
Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 665 Solved: 307
[Submit][Status][Discuss]
Description
现在有一棵二叉树,所有非叶子节点都有两个孩子。在每个叶子节点上有一个权值(有n个叶子节点,满足这些权值为1..n的一个排列)。可以任意交换每个非叶子节点的左右孩子。
要求进行一系列交换,使得最终所有叶子节点的权值按照中序遍历写出来,逆序对个数最少。
Input
第一行n
下面每行,一个数x
如果x==0,表示这个节点非叶子节点,递归地向下读入其左孩子和右孩子的信息,
如果x!=0,表示这个节点是叶子节点,权值为x。
Output
一行,最少逆序对个数。
Sample Input
3
0
0
3
1
2
0
0
3
1
2
Sample Output
1
HINT
对于100%的数据:2<=n<=200000。
Source
直接上线段树合并即可
https://www.cnblogs.com/Mychael/p/8665589.html
/**************************************************************
Problem: 3702
User: zhangenming
Language: C++
Result: Accepted
Time:7324 ms
Memory:86028 kb
****************************************************************/
#include <bits/stdc++.h>
#define ll long long
#define inf 1e9+10
#define ull unsigned long long
#define eps 1e-7
using namespace std;
inline int read(){
int x=0;int f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=1e6+10;
struct sig{
int sum,ls,rs;
}T[MAXN<<2];
int rt[MAXN],n,l[MAXN],r[MAXN],vl[MAXN],tot,siz;
ll sum1,sum2,ans;
inline void build(int &x){
int t=read();x=++tot;
if(t==0) build(l[x]),build(r[x]);
else vl[x]=t;
}
inline void ins(int l,int r,int &rt,int t){
if(!rt) rt=++siz;
T[rt].sum++;
if(l==r) return;
int mid=(l+r)>>1;
if(t<=mid) ins(l,mid,T[rt].ls,t);
else ins(mid+1,r,T[rt].rs,t);
}
inline int merge(int x,int y){
if(!x||!y) return x+y;
sum1+=1LL*T[T[x].rs].sum*T[T[y].ls].sum;
sum2+=1LL*T[T[x].ls].sum*T[T[y].rs].sum;
T[x].sum+=T[y].sum;
T[x].ls=merge(T[x].ls,T[y].ls);
T[x].rs=merge(T[x].rs,T[y].rs);
return x;
}
inline void dfs(int x){
if(vl[x]){
ins(1,n,rt[x],vl[x]);
}
else{
dfs(l[x]);dfs(r[x]);
sum1=sum2=0;
rt[x]=merge(rt[l[x]],rt[r[x]]);
ans+=min(sum1,sum2);
}
}
int main(){
n=read();
int root;
build(root);
dfs(root);
printf("%lld\n",ans);
return 0;
}